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

发布于 2024-07-05 08:23:03 字数 303 浏览 8 评论 0原文

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

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

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

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

How do you implement an efficient and thread safe reference counting system on X86 CPUs in the C++ programming language?

I always run into the problem that the critical operations not atomic, and the available X86 Interlock operations are not sufficient for implementing the ref counting system.

The following article covers this topic, but requires special CPU instructions:

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

风启觞 2024-07-12 08:23:03

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

具体来说,如果您不能保证智能指针在分配给另一个智能指针时不会发生变化,那么您就做错了,或者一开始就做了一些非常不可靠的事情。 如果智能指针在分配给另一个智能指针时可以更改,则意味着执行分配的代码不拥有该智能指针,这从一开始就值得怀疑。

That particular code posted in that ddj article is adding extra complexity to account for bugs in using smart pointers.

Specifically, if you can't guarantee that the smart pointer won't change in an assignment to another smart pointer, you are doing it wrong or are doing something very unreliable to begin with. If the smart pointer can change while being assigned to another smart pointer, that means that the code doing the assignment doesn't own the smart pointer, which is suspect to begin with.

千年*琉璃梦 2024-07-12 08:23:03

如果指令本身不是原子的,那么您需要将更新适当变量的代码部分设置为关键部分。

ie 您需要通过使用某种锁定方案来防止其他线程进入该代码段。 当然,锁必须是原子的,但您可以在 pthread_mutex 类中找到原子锁定机制。

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

贵吗:大概。 但凡是需要保证的事情都是有成本的。

If the instruction itself is not atomic then you need to make the section of code that updates the appropriate variable a critical section.

i.e. You need to prevent other threads entering that section of code by using some locking scheme. Of course the locks need to be atomic, but you can find an atomic locking mechanism within the pthread_mutex class.

The question of efficient: The pthread library is as efficient as it can be and still guarantee that mutex lock is atomic for your OS.

Is it expensive: Probably. But for everything that requires a guarantee there is a cost.

站稳脚跟 2024-07-12 08:23:03

Win32 InterlockedIncrementAcquire 和 InterlockedDecrementRelease (如果你想安全并关心可能重新排序的平台,因此你需要同时发出内存屏障)或 InterlockedIncrement 和 InterlockedDecrement (如果你确定你将保持 x86),是原子的并且将做这份工作。

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

Win32 InterlockedIncrementAcquire and InterlockedDecrementRelease (if you want to be safe and care about platforms with possible reordering, hence you need to issue memory barriers at the same time) or InterlockedIncrement and InterlockedDecrement (if you are sure you will stay x86), are atomic and will do the job.

That said, Boost/TR1 shared_ptr<> will handle all of this for you, therefore unless you need to implement it on your own, you will probably do the best to stick to it.

兔小萌 2024-07-12 08:23:03

请记住,锁定的成本非常高,每次在智能指针之间传递对象时都会发生这种情况 - 即使该对象当前由一个线程拥有(智能指针库不知道这一点)。

鉴于此,这里可能有一条适用的经验法则(我很高兴得到纠正!)

如果以下情况适用于您:

  • 您有复杂的数据结构,很难为其编写析构函数(或者 STL 样式值根据设计,语义是不合适的),因此您需要智能指针来为您完成此操作,并且
  • 您正在使用共享这些对象的多个线程,并且
  • 您关心性能和正确性

......那么实际的垃圾收集可能是更好的选择。 尽管 GC 在性能方面名声不佳,但这都是相对的。 我相信它与锁定智能指针相比非常有利。 这是 CLR 团队选择真正的 GC 而不是使用引用计数的一个重要原因。 请参阅本文,特别是如果您正在进行计数:

无引用计数:

a = b;

引用计数:

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

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

a = b;

Bear in mind that the locking is very expensive, and it happens every time you hand objects around between smart pointers - even when the object is currently owned by one thread (the smart pointer library doesn't know that).

Given this, there may be a rule of thumb applicable here (I'm happy to be corrected!)

If the follow things apply to you:

  • You have complex data structures that would be difficult to write destructors for (or where STL-style value semantics would be inappropriate, by design) so you need smart pointers to do it for you, and
  • You're using multiple threads that share these objects, and
  • You care about performance as well as correctness

... then actual garbage collection may be a better choice. Although GC has a bad reputation for performance, it's all relative. I believe it compares very favourably with locking smart pointers. It was an important part of why the CLR team chose true GC instead of something using reference counting. See this article, in particular this stark comparison of what reference assignment means if you have counting going on:

no ref-counting:

a = b;

ref counting:

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

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

a = b;
但可醉心 2024-07-12 08:23:03

在 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 指令使用适当的内部函数。

In VC++, you can use _InterlockedCompareExchange.

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

On other platforms/compilers, use the appropriate intrinsic for the LOCK CMPXCHG instruction that MS's _InterlockedCompareExchange exposes.

心奴独伤 2024-07-12 08:23:03

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

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

Strictly speaking, you'll need to wait until C++0x to be able to write thread-safe code in pure C++.

For now, you can use Posix, or create your own platform independent wrappers around compare and swap and/or interlocked increment/decrement.

演出会有结束 2024-07-12 08:23:03

现在,您可以使用Boost/TR1的shared_ptr<> 智能指针来保持你的引用计数引用。

效果很好; 没有大惊小怪,没有混乱。 该shared_ptr<> 类负责引用计数所需的所有锁定。

Nowadays, you can use the Boost/TR1 shared_ptr<> smart pointer to keep your reference counted references.

Works great; no fuss, no muss. The shared_ptr<> class takes care of all the locking needed on the refcount.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文