如何在C++编程语言中实现一个高效且线程安全的引用计数系统?
我经常遇到一个问题,即关键操作不是原子的,而且可用的X86互锁操作不足以实现引用计数系统。
下面的文章涵盖了这个主题,但需要特殊的CPU指令:
如何在C++编程语言中实现一个高效且线程安全的引用计数系统?
我经常遇到一个问题,即关键操作不是原子的,而且可用的X86互锁操作不足以实现引用计数系统。
下面的文章涵盖了这个主题,但需要特殊的CPU指令:
在VC++中,您可以使用_InterlockedCompareExchange函数。
do
read the count
perform mathematical operation
interlockedcompareexchange( destination, updated count, old count)
until the interlockedcompareexchange returns the success code.
在其他平台/编译器上,使用适当的内置函数来执行LOCK CMPXCHG指令,这与MS的_InterlockedCompareExchange函数相对应。
严格来说,要想在纯C++中编写线程安全的代码,您需要等到C++0x版本。
目前,您可以使用Posix,或者创建自己的平台无关包装器,围绕比较和交换以及/或者原子增量/减量进行操作。
如果你想要安全并且在可能重新排序的平台上关注,因此需要同时发出内存屏障,那么Win32 InterlockedIncrementAcquire和InterlockedDecrementRelease将是原子操作,并且可以完成工作。如果你确定会保持x86,则可以使用InterlockedIncrement和InterlockedDecrement。
话虽如此,Boost/TR1 shared_ptr<>将为你处理所有这些问题,因此除非你需要自己实现它,否则最好坚持使用它。
a = b;
引用计数:
if (a != null)
if (InterlockedDecrement(ref a.m_ref) == 0)
a.FinalRelease();
if (b != null)
InterlockedIncrement(ref b.m_ref);
a = b;
InterlockedDecrement(...)
和a.FinalRelease();
之间引用时会发生什么? - smokkua = b
。如果两个线程有足够的权限访问对象以增加计数,则计数已经> = 2。任何一个都可以将其减少,但这样做同时放弃了增加它的能力。 - Daniel EarwickerInterlockedDecrement(...)
和a.FinalRelease();
之间执行a = b
会发生什么? - smokku如果指令本身不是原子的,那么您需要将更新适当变量的代码部分设置为临界区。
即,您需要使用某些锁定方案防止其他线程进入该代码部分。当然,锁必须是原子的,但您可以在pthread_mutex类中找到原子锁定机制。
效率问题:pthread库尽可能高效,同时保证互斥锁对于您的操作系统是原子的。
是否昂贵:可能。但对于需要保证的所有内容都有一个成本。
那篇DDJ文章中发布的特定代码为解决使用智能指针时出现的错误增加了额外的复杂性。
具体来说,如果您无法保证智能指针在分配给另一个智能指针时不会更改,则您正在做错事情或者一开始就在做非常不可靠的事情。如果智能指针在被分配给另一个智能指针时可以更改,这意味着执行分配操作的代码并不拥有该智能指针,这本身就是可疑的。