5

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

我的代码是:

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;

我错了吗?

4

2 回答 2

2

当心 !

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

我已经看到像您问题中那样的代码,结果非常糟糕......

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

my2c

于 2011-02-08T16:20:52.017 回答
1

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

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

您需要避免手动删除和使对象无效,并更好地使用一些意识到并发的智能指针实现来处理引用计数。

每当指针检测到引用计数为零时,您需要锁定对象以避免被其他线程引用,就像初始化新引用的双重检查锁定一样。

于 2011-02-08T16:17:52.220 回答