C++ 在多个线程中使用它安全吗?

C++ 在多个线程中使用它安全吗?,c++,multithreading,boost,shared-ptr,C++,Multithreading,Boost,Shared Ptr,我试图找到答案已经有一段时间了,但我失败了 假设我们有一个从一个线程创建的共享\u ptr。然后我们将这个shared_ptr传递给另外两个线程(例如使用一些队列)。因此,从这一刻起,有两份原始的共享的\u ptr,指向同一个原始指针。 两个所有者线程都将从队列中获取此共享\u ptr的副本。然后他们将把它传递给另一个线程,或者将其销毁 问题是——它安全吗?原始指针是否正确销毁(将不会与引用计数器竞争?) C++标准对线程安全性几乎没有保证。std::shared_ptr的引用计数是唯一的例外:

我试图找到答案已经有一段时间了,但我失败了

假设我们有一个从一个线程创建的
共享\u ptr
。然后我们将这个
shared_ptr
传递给另外两个线程(例如使用一些队列)。因此,从这一刻起,有两份原始的
共享的\u ptr
,指向同一个原始指针。 两个所有者线程都将从队列中获取此
共享\u ptr
的副本。然后他们将把它传递给另一个线程,或者将其销毁

问题是——它安全吗?原始指针是否正确销毁(将不会与引用计数器竞争?)
C++标准对线程安全性几乎没有保证。
std::shared_ptr
的引用计数是唯一的例外:它保证作为一个原子访问变量。我认为这一点已被编纂在§20.7.2.2/4中的这一短语中:

use\u count()
中的更改并不反映可能引入数据竞争的修改

boost::共享\u ptr

共享的_ptr对象提供与内置类型相同级别的线程安全性。共享的_ptr实例可以由多个线程同时“读取”。不同的共享_ptr实例可以由多个线程同时“写入”…(即使这些实例是副本,并且在下面共享相同的引用计数)

国家:

不同的共享ptr实例可以由多个线程同时“写入”(使用可变操作(如operator=或reset)访问)(即使这些实例是副本,也可以共享下面相同的引用计数。

(强调矿山)


因此,这里的关键在于是否在线程之间复制
boost::shared_ptr
s。如果您创建副本(使用
shared\ptr
s的“安全”方式),您就不会担心线程安全。但是,如果您通过引用或指针传递
shared_ptr
,因此在不同的线程中使用实际相同的
shared_ptr
,您将不得不担心线程安全,如文档中所述。

我想在多线程用例中发布我对boost共享指针中引用计数的评论。该评论旨在回答“boost共享指针引用计数中是否存在争用条件”的问题

对于大多数主流编译器,我的简单答案是“不”,至少在Boost1.35之后是这样。boost/detail/shared_count.hpp中定义的名为“add_ref_copy”的boost实现。此函数将调用为单个编译器定义的相应原子函数。例如,windows版本将调用“BOOST\u INTERLOCKED\u INCREMENT”以原子方式增加计数(请参阅详细信息\sp\u counted\u base\u w32.hpp)。Linux gcc for X86将调用原子增量(…)(请参阅详细信息\sp\u counted\u base\u gcc\u X86.hpp)。每个编译器都实现了线程安全机制,以确保引用计数以有效的方式更新。有些代码甚至是用汇编语言编写的


现在在我的简单回答中有一个警告。您确实需要确保您的编译器包含在boost的幸运列表中,以便进行多线程安全引用计数。如果您不确定是否可以定义“BOOST\u SP\u USE\u PTHREADS”,这将促使BOOST使用pthread库进行原子化的引用计数更新(包括pthread解决方案的BOOST/detail/SP\u counted\u base\u pt.hpp)。

OP询问的是
BOOST::shared\u ptr
。我希望行为会是一样的,但最好清楚一点。@juan很好,但您提供的链接明确表示OP想要使用的操作是安全的。20.7.2.5在这里也很有趣:“如果通过本节中的函数以独占方式访问共享的\u ptr对象,并且实例作为其第一个参数传递,则从多个线程并发访问共享的\u ptr对象不会导致数据争用。”对于
共享的\u ptr
,不存在特定的保证。该保证适用于每个标准类。”SyddypTR保证有原子引用计数“NAH。显然不能保证<代码> SyddypTr> /Cuffe”甚至使用计数器。“没有其他标准类具有可比性保证”NAH。每个其他C++结构,无论是核心还是库,都提供完全相同的保证:实现不应引入数据竞争。(当然,如果源代码中没有)。“没有其他标准类描述包含可与§20.7.2.2/4相媲美的措辞,”甚至没有
try_lock
?您的表述有点含糊不清:“销毁”,您的意思是调用
reset
、分配新的指针对象还是让
共享的\u ptr
超出范围?如果是这样,这些操作就可以了。其他破坏性操作可能不会。我不计划任何reset()call.shared_ptr超出范围。我创建副本并将它们放在线程队列中。然后从队列中获取副本。