线程安全引用计数的另一个问题

时间:2011-02-08 15:29:55

标签: c++ multithreading refcounting

关于如何实现线程安全引用计数器,有很多问题。 一个常见的高度评价的答案是:“使用原子增量/减量”。 好的,这是一个很好的方法来读取和写入refCounter whitout其他线程在其间更改它。但

我的代码是:

void String::Release()
{
    if ( 0 == AtomicDecrement( &refCounter ) ) )
        delete buffer;
}

因此。我安全地减少并阅读refCounter。但是,如果我将其与零????

进行比较,那么其他线程会增加我的refCounter

我错了吗?

编辑:(示例)

String* globalString = new String(); // refCount == 1 after that.

// thread 0:
delete globalString; 
  // This invokes String::Release().
  // After AtomicDecrement() counter becomes zero. 
  // Exactly after atomic decrement current thread switches to thread 1.

// thread 1:
String myCopy = *globalString;
  // This invokes AddRef(); 
  // globalString is alive;
  // internal buffer is still not deleted but refCounter is zero;
  // We increment and switch back to thread 0 where buffer will be 
  // succefully deleted;

我错了吗?

2 个答案:

答案 0 :(得分:2)

小心!

仅保护像参考计数器这样的变量来管理更大的生命周期是不够的。

我看到你的问题中的代码非常糟糕......

在你的情况下,不仅有人可以在比较后增加计数器,但是某些线程可以获得值为1的计数器,然后你减少并删除缓冲区而另一个线程使用已删除的内存... CRASH

MY2C

答案 1 :(得分:1)

你的例子听起来对我不错。

但是,这里的问题不是关于原子操作,而是手动删除对象然后引用即将删除的对象。如果引用计数而不是1,那么该怎么办?

您需要避免手动删除和使对象无效,并且最好使用一些智能指针实现并发处理引用计数。

每当指针检测到refcount为零时,您需要锁定该对象以避免被其他线程引用,就像double-checked locking初始化新引用一样。