我是多线程编程的新手,我仍然对此感到困惑。
以下是我的参考计数类:
class Rbuffer
{
private:
char *m_pnData;
volatile unsigned int mRefCount;
public:
Rbuffer(int nLength) : mRefCount(0)
{
m_pnData = new char[nLength];
}
~Rbuffer(){
delete[] m_pnData;
}
void decRef() {
if(InterlockedDecrement(&mRefCount)==0){
delete (Rbuffer *)this;
}
}
void incRef() {
InterlockedIncrement(&mRefCount);
}
};
它是完全线程安全的吗?你能否排除这种情况:
ThreadA ThreadB
PointerToRBuffer->incRef();//mRefCount 1
switch->
PointerToRBuffer->incRef();//mRefCount 2
<-switch
PointerToRBuffer->decRef();
InterlockedDecrement(&mRefCount)//mRefCount 1
switch->
PointerToRBuffer->decRef();//mRefCount 0!
InterlockedDecrement(&mRefCount);
if (0==0)
delete (Rbuffer *)this;
<-switch
if (0==0)
//deleting object, that doesn't exist
delete (Rbuffer *)this;
//CRASH
崩溃的原因可能是只有(InterlockedDecrement(&amp; mRefCount))部分是原子的,但是 if(InterlockedDecrement(&amp; mRefCount)== 0)不? 我上面的例子错了吗?
提前感谢您的意见和建议,以使我的课程完全安全。
答案 0 :(得分:3)
你的分析不对;您发布的代码正确使用interlockedDecrement
。
这是一种安全使用
if(InterlockedDecrement(&mRefCount)==0)
cleanup();
..但这确实会有你描述的问题
InterlockedDecrement(&mRefCount);
if (mRefCount==0)
cleanup();
然而,delete this
的使用更可能是导致问题的原因。您不太可能通过此处描述的“绝对肯定100%肯定”测试:
http://www.parashift.com/c++-faq-lite/delete-this.html
特别是,以下简单代码会导致混乱。
{
RBuffer x; // count is what... ? zero
x.incRef(); // make count one
x.decRef(); // make count zero, and deletes itself
} // now x goes out of scope, so destructor is called a second time = chaos!
正常的“引用计数”习惯涉及“共享对象”(带有计数),以及引用共享对象的简单“引用对象”(不是C ++引用,尽管语义相似)。 “引用对象”的构造函数和析构函数负责调用共享对象上的incref/decref
方法。因此,共享对象会自动计算活动“引用对象”的数量。
答案 1 :(得分:2)
它不是100%清楚发生了什么,但看起来ThreadA删除了RBuffer对象,然后ThreadB取消引用它。
你真正需要的是关于递减和删除操作的互斥,此外你需要设置某种标志以防止删除后取消引用。通常将指针设置为NULL,然后在任何取消引用之前检查NULL。
所以你的decRef可能看起来像这样:
void decRef() {
lock(_mutex);
if(InterlockedDecrement(&mRefCount)==0) {
PointerToRBuffer = NULL;
delete (Rbuffer *)this;
}
}
使用shared_ptr可能会更好。