引用计数类和多线程 [英] reference counted class and multithreading

查看:269
本文介绍了引用计数类和多线程的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述



下面是我的引用计数类:

  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(){
InterlockedIntrement(& 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)
//删除对象,不存在
delete(Rbuffer *)this;
// CRASH

崩溃的原因可能是(InterlockedDecrement & mRefCount))部分是原子,但 if(InterlockedDecrement(& mRefCount)== 0)不是?
上面的例子错了吗?



提前感谢您的意见和建议,使我的类完全线程安全。

解决方案

您的分析不正确;您发布的代码正在使用 interlockedDecrement



这是一个安全使用

  if(InterlockedDecrement(& mRefCount)== 0)
cleanup();

..但这确实会有你描述的问题

  InterlockedDecrement(& mRefCount); 

if(mRefCount == 0)
cleanup();

但是,使用删除此更可能是问题的原因。你不可能通过这里描述的绝对肯定的100%肯定测试:
http://www.parashift.com/c++-faq-lite/delete-this.html



特别是,以下简单代码将导致混乱。

  {
RBuffer x; // count是什么...? zero
x.incRef(); // make count one
x.decRef(); // make count zero,and deletes itself
} //现在x超出范围,所以析构函数被第二次调用= chaos!

一个正常的引用计数成语涉及一个共享对象 '引用对象'(不是C ++引用,虽然语义将是类似的),它们指的是共享对象。 引用对象的构造函数和析构函数负责调用共享对象上的 incref / decref 方法。因此,共享对象会自动计算活动引用对象的数量。


I 'm a novice in multithreading programing and i have still confusion with that.

Below is my reference counted class:

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);
    } 

}; 

is it fully thread safe? Can you exclude this situation:

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                               

The reasons of crashing could be that only (InterlockedDecrement(&mRefCount)) part is atomic, but if (InterlockedDecrement(&mRefCount)==0) not? Am i wrong with example above?

Thanks in advance for your opinions and advice to make my class fully thread safe.

解决方案

Your analysis isn't right; The code you posted is using interlockedDecrement correctly.

This is a safe use

 if(InterlockedDecrement(&mRefCount)==0)
           cleanup();

.. but this would indeed have the problem you described

 InterlockedDecrement(&mRefCount);

 if (mRefCount==0)
           cleanup();

However, the use of delete this is much more likely to be the cause of the problem. It's very unlikely you're passing the 'absolutely positively 100% sure' tests described here: http://www.parashift.com/c++-faq-lite/delete-this.html

In particular, the following simple code would cause chaos.

{
  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! 

A normal "reference counting" idiom involves a 'shared object' (with the count), and simple 'reference objects' (not C++ references, although the semantics would be similar) which refer to the shared object. The constructors and destructors of the 'reference objects' are responsible for calling the incref/decref methods on the shared object. So the shared object is automatically counting the number of active 'reference objects'.

这篇关于引用计数类和多线程的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆