有谁知道一个完全线程安全shared_ptr实施的?例如。 shared_ptr的提升实现是线程安全的目标(引用计数),并且还安全的同时shared_ptr例如读取,但不能写入或读/写。

(参见升压文档,实例3,4和5)。

有一个shared_ptr实现,完全线程安全shared_ptr实例?

奇怪的是,提高文档说:

  

shared_ptr对象提供线程安全的相同的水平内置类型。

但是,如果你比较普通指针(内置式),以smart_ptr,一个普通的指针,然后同时写入是线程安全的,但是到了smart_ptr同时写入是没有的。

编辑:我的意思是在x86架构的无锁的实施

EDIT2:一个实例用例对于这样的智能指针将是其中有许多工作线程,其更新与它们的当前工作项和监视器的线程,是以工作项的随机样本的全局的shared_ptr。直到另一个工作项指针分配给它(从而破坏以前的工作项)共享PTR将自己的工作项目。显示器会被其分配给自己的共享PTR获得工作项(从而防止被破坏的工作项)的所有权。它可以与XCHG和手动删除来完成,但将是很好,如果一个共享PTR可以做到这一点。

另一个例子是在全局共享-PTR持有“处理器”,并且由某个线程分配,并通过一些其它线程使用。当“用户”线程看到的是,处理器碎片-PTR为NULL,则使用一些备选逻辑做加工。如果它不是NULL,它可以防止处理器通过将其分配到它自己的共享-PTR的破坏。

有帮助吗?

解决方案

添加这样一个完全线程安全的shared_ptr执行可能会影响性能必要的障碍。考虑下面的比赛(注意:伪盛产):

主题1:     global_ptr = A;

主题2:     global_ptr = B;

主题3:     local_ptr = global_ptr;

如果我们打破这种分解为其构成成分的操作:

主题1:

A.refcnt++;
tmp_ptr = exchange(global_ptr, A);
if (!--tmp_ptr.refcnt) delete tmp_ptr;

主题2:

B.refcnt++;
tmp_ptr = exchange(global_ptr, B);
if (!--tmp_ptr.refcnt) delete tmp_ptr;

主题3:

local_ptr = global_ptr;
local_ptr.refcnt++;

显然,如果线程3之后A的交换读取指针,则B变为与所述参考计数之前删除它可以递增,坏的事情会发生。

要解决这个问题,我们需要一个伪值,而线3是做refcnt更新要使用的: (注意:compare_exchange(变量,预期新)采用全新的可变原子取代的价值,如果它是当前等于新的,那么如果它这样做成功返回true)

主题1:

A.refcnt++;
tmp_ptr = global_ptr;
while (tmp_ptr == BAD_PTR || !compare_exchange(global_ptr, tmp_ptr, A))
    tmp_ptr = global_ptr;
if (!--tmp_ptr.refcnt) delete tmp_ptr;

主题2:

B.refcnt++;
while (tmp_ptr == BAD_PTR || !compare_exchange(global_ptr, tmp_ptr, A))
    tmp_ptr = global_ptr;
if (!--tmp_ptr.refcnt) delete tmp_ptr;

主题3:

tmp_ptr = global_ptr;
while (tmp_ptr == BAD_PTR || !compare_exchange(global_ptr, tmp_ptr, BAD_PTR))
    tmp_ptr = global_ptr;
local_ptr = tmp_ptr;
local_ptr.refcnt++;
global_ptr = tmp_ptr;

您现在已经不得不在它在你的/读/操作的中间增加一个循环,与原子能。这是不是一件好事 - 它可以在某些CPU非常昂贵。更重要的是,你忙等待为好。你可以开始弄巧用futexes的和诸如此类的东西 - 但到那个时候你已经改造了锁

这个成本,这必须由每个操作负担,而且在本质上是什么锁会给你无论如何非常相似,所以你一般看不到这样的线程安全的shared_ptr实现。如果你需要这样的事情,我会建议包装一个互斥体和shared_ptr的为方便类自动锁定。

其他提示

到一个内置的指针同时写入肯定不是线程安全的。考虑相对于内存屏障写入相同值的影响,如果你真的想自己开车疯狂的(例如,你可以有两个线程想同样的指针有不同的值)。

RE:评论 - 原因内置插件不删除两倍,是因为他们根本不被删除(我使用boost :: shared_ptr的实施不会增加一倍删除,因为它使用了一个特殊的原子递增和减量,所以它只能单删除,但随后的结果将有可能从一个指针和其他的引用计数,或者几乎是二者的任意组合,这将是坏的。)。在升压文档的说法是正确的,因为它是,你会得到同样的保障,你有一个内置的事。

RE:EDIT2 - 你所描述的第一种情况是使用内置插件和shared_ptrs之间非常不同。在一个(XCHG和手动删除)没有引用计数;我们假定你是你是独一无二的所有者,当你做到这一点。如果使用共享指针,你说其他线程可能有所有权,这使得更加复杂的事情。我相信这是可能的一个比较并交换,但这将是非常不便于携带。

的C ++ 0x是走出与原子能库,这应该使它更容易编写通用多线程代码。你可能得等到散发出来看线程安全的智能指针的良好的跨平台的参考实现。

我不知道这样的智能指针实现的,但我要问:这种行为怎么可能是有用的?我能想到的,你会发现同时指针更新的唯一情况是竞态条件(即错误)。

这是不是批评 - 有可能是一个合法的使用情况下,我不能把它。请让我知道!

回复:EDIT2 谢谢你提供了几个方案。这听起来像原子写入指针会在这些情况下非常有用。 (一个小东西:对第二个例子,当你写“如果它不是NULL,它可以防止处理器通过将其分配给自己的共享PTR被销毁”,我希望你的意思是你指定全局共享指针本地共享指针第一然后检查本地共享指针是否为NULL - 你所描述的方式很容易出现在全局共享指针变为NULL您测试之后的争用条件和分配之前到本地之一。)

您可以使用此实现原子引用计数指针来至少实现引用计数机构。

您编译器可能已经提供的螺纹较新的C ++标准安全智能指针。我相信 TBB 是在加入了智能指针的规划,但我不认为它被列入呢。您可以使用TBB的线程安全的容器之一,虽然。

可以很容易地通过包括与每一个共享一个指针互斥对象,和包装增量/减量与锁定命令这样做。

我不觉得这很容易,这是不够用CS来包装你sh_ptr类。这是事实,如果你保持一个单一的CS为所有共享指针它可以确保避免在不同的线程之间sh_ptr对象的相互访问和删除。但是,这将是可怕的,对于每一个共享指针一个CS对象将是一个真正的瓶颈。这将是合适的,如果每一个可包装的新PTR -s有不同的CS S'但这样一来,我们应该dinamically创造我们的CS,并确保sh_ptr类的副本构建函数来发送这个共享铯。现在,我们到达了同样的问题:谁quaranties这Cs的PTR已被删除或没有。我们可以多一点智者每例如挥发性m_bReleased标志,但这样一来,我们不能陷检查标志,并使用共享铯之间的安全差距。我看不出这个问题彻底解决安全。也许这可怕的全球铯将是轻微的坏杀死的应用程序。 (抱歉,我的英语)

这可能不是你想要什么,但boost::atomic文档提供了有关如何使用原子计数器与intrusive_ptr一个例子。 intrusive_ptr是升压智能指针中的一个,但它确实“侵入引用计数”,这意味着计数器被“嵌入”在目标,而不是由智能指针提供。

升压atomic使用示例:

http://www.boost.org/doc/html/atomic/ usage_examples.html

在我看来,最简单的解决方案是使用一个intrusive_ptr有一些小的(但有必要)的修改。

我共享我的实现如下:

http://www.philten.com/boost-smartptr-mt/

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top