如何在C ++中实现线程安全引用计数

时间:2008-09-18 14:33:15

标签: c++ multithreading atomic reference-counting

如何在C ++编程语言的X86 CPU上实现高效且线程安全的引用计数系统

我总是遇到关键操作不是原子的问题,而且可用的X86 Interlock操作不足以实现引用计数系统。

以下文章介绍了此主题,但需要特殊的CPU说明:

http://www.ddj.com/architect/184401888

7 个答案:

答案 0 :(得分:11)

如今,您可以使用Boost / TR1 shared_ptr<>智能指针,以保持您的参考计数参考。

效果很好;没有大惊小怪,没有麻烦。 shared_ptr<> class负责引用refcount所需的所有锁定。

答案 1 :(得分:4)

在VC ++中,您可以使用_InterlockedCompareExchange

do
   read the count
   perform mathematical operation
   interlockedcompareexchange( destination, updated count, old count)
until the interlockedcompareexchange returns the success code.

在其他平台/编译器上,使用MS的_InterlockedCompareExchange公开的LOCK CMPXCHG指令的相应内在函数。

答案 2 :(得分:3)

严格来说,您需要等到C ++ 0x才能在纯C ++中编写线程安全的代码。

目前,您可以使用Posix,或围绕比较和交换和/或互锁增量/减量创建自己的平台独立包装。

答案 3 :(得分:2)

Win32 InterlockedIncrementAcquire和InterlockedDecrementRelease(如果你想要安全并关心可能重新排序的平台,因此你需要同时发出内存障碍)或InterlockedIncrement和InterlockedDecrement(如果你确定你会留下x86),原子,并将完成这项工作。

那就是说,Boost / TR1 shared_ptr<>将为您处理所有这些,因此除非您需要自己实施,否则您可能会尽力坚持下去。

答案 4 :(得分:1)

请记住,锁定非常昂贵,并且每次在智能指针之间处理对象时都会发生 - 即使对象当前由一个线程拥有(智能指针库也不知道)。 p>

鉴于此,这里可能有一条经验法则(我很乐意予以纠正!)

如果以下内容适用于您:

  • 你有很复杂的数据结构很难编写析构函数(或者STL风格的值语义不合适,因此你需要智能指针来为你做,
  • 您正在使用共享这些对象的多个线程,
  • 你关心表现和正确性

...然后实际的垃圾收集可能是更好的选择。尽管GC在性能上有不好的声誉,但它们都是相对的。我相信它与锁定智能指针相比非常有利。这是CLR团队为什么选择真正的GC而不是使用引用计数的一个重要部分。请参阅this article,特别是如果你有计算的话,这个参考分配意味着什么的明显比较:

没有重新计算:

a = b;

重新计算:

if (a != null)
    if (InterlockedDecrement(ref a.m_ref) == 0)
            a.FinalRelease();

if (b != null)
    InterlockedIncrement(ref b.m_ref);

a = b;

答案 5 :(得分:0)

如果指令本身不是原子的,那么你需要将更新相应变量的代码部分作为关键部分。

您需要使用某种锁定方案阻止其他线程进入该部分代码。当然锁需要是原子的,但你可以在pthread_mutex类中找到一个原子锁机制。

高效的问题:pthread库尽可能高效,并且仍然保证互斥锁对于您的操作系统来说是原子的。

价格昂贵:可能。但是对于需要保证的一切都需要付出代价。

答案 6 :(得分:0)

该ddj文章中发布的特定代码增加了额外的复杂性,以解决使用智能指针时的错误。

具体来说,如果您无法保证智能指针在分配给另一个智能指针时不会改变,那么您做错了或者做了一些非常不可靠的事情。如果智能指针在被分配给另一个智能指针时可以改变,这意味着执行赋值的代码不拥有智能指针,这是可疑的开始。