C++ Boost共享指针:跨多个线程同时读取访问

C++ Boost共享指针:跨多个线程同时读取访问,c++,multithreading,boost,shared-ptr,C++,Multithreading,Boost,Shared Ptr,我有一个线程a,它分配内存并将其分配给共享指针。然后该线程生成其他3个线程X、Y和Z,并将共享指针的副本传递给每个线程。当X、Y和Z超出范围时,内存被释放。但是有没有可能2个线程X,Y在完全相同的时间点超出作用域,并且引用计数上存在竞争条件,因此不是将其递减2,而是只递减一次。因此,现在引用计数下降到0,因此存在内存泄漏。请注意,X、Y和Z仅读取内存。未写入或重置共享指针。长话短说,引用计数是否存在争用条件,是否会导致内存泄漏?否,根据,这些问题不会发生: 不同的shared_ptr实例可以由多

我有一个线程a,它分配内存并将其分配给共享指针。然后该线程生成其他3个线程X、Y和Z,并将共享指针的副本传递给每个线程。当X、Y和Z超出范围时,内存被释放。但是有没有可能2个线程X,Y在完全相同的时间点超出作用域,并且引用计数上存在竞争条件,因此不是将其递减2,而是只递减一次。因此,现在引用计数下降到0,因此存在内存泄漏。请注意,X、Y和Z仅读取内存。未写入或重置共享指针。长话短说,引用计数是否存在争用条件,是否会导致内存泄漏?

否,根据,这些问题不会发生:

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


boost::shared_ptr
使用锁(或无锁原子访问)来确保引用计数以原子方式更新(即使文档页面中没有明确)。如果编写单线程代码,可以通过定义宏
BOOST\u SP\u DISABLE\u THREADS
配置锁的使用

请注意,中讨论来自不同线程的多次写入问题的文档示例正在讨论那些作用于相同
共享ptr
实例的线程(示例中的
共享ptr
对象可能是全局对象),而不是指向同一对象的不同
共享ptr
副本,这是
共享\u ptr
的常用用例。您在问题中给出的示例(对指向共享对象的副本执行操作)是线程安全的。

说明:

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


因此,如果没有一个线程访问其他线程的指针对象,那么就可以了。请查看文档中的示例,看看哪一个与您的案例相关。

其他几个人已经提供了指向文档的链接,说明这是安全的


要获得绝对无可辩驳的证据,请参阅Boost Smartptr如何在
Boost/smart\u ptr/detail/sp\u counted\u base\u gcc\u x86.hpp
(或您平台的相应文件)中从头开始实现自己的互斥锁。

最好的办法是升级到TR1或C++0x共享\u ptr,而不是Boost。我相信这些必须是线程安全的,这是标准化的。

但是我有一个问题:根据文档,混合的情况可能导致未定义的beahvior:(…)//--示例4---//线程a p3=p2;///读取p2,写入p3//thread B//p2超出范围:未定义,析构函数被视为“写访问”(…)我们不是处于这种情况吗?下面的示例显示了超出范围时行为为“未定义”。@Grimmy,@Brian:据我所知,在文档的示例4中,一个线程试图读取另一个线程中的
shared_ptr
变量,而这个变量超出了范围。这将是未定义的(对于其他类型的变量,它也将是未定义的,不仅仅是
shared\u ptr
)。如果每个线程都有自己的
shared_ptr
变量副本,那么即使这些变量指向同一个对象(如文档中的示例2),也可以单独使用(并超出范围)。有趣的是,两个人使用相同的文档得出了相反的结论。@Mark:我想说这些文档并不完全清晰(不是说它们是错的,只是它们很容易被误解)。我不明白你为什么要问bounty这个问题。答案已经在那里:)希望能有一个更具描述性的答案,也许是一个代码片段。。这只是一个小小的激励,只有100分。评论完全正确,但我还要补充一点,从“错误”线程或在“错误”时间调用某些对象的析构函数可能会产生常见的多线程错误,如争用和死锁。如果被破坏的对象只释放内存,这应该不是问题。但是,析构函数做的事情,比如在系统的其他部分取消注册注定要失败的对象,肯定会导致问题。@Doug,但这与
共享\u ptr
无关。最好从锁定的独占访问的角度考虑,而不是“它崩溃是因为它在错误的时间出现在错误的位置。”析构函数访问的任何资源都应该自己锁定。@Potatoswatter:是的,我知道我提出的问题与共享线程的线程安全没有直接关系。我不认为比赛条件是“在错误的时间在错误的地点”。我发现了由共享线程引起的bug,它们丢失了(比如)非主线程上的最后一个引用,析构函数在其中执行非平凡的清理。这与手动删除指针完全相同,正如文档中所说的“与原始指针具有相同的线程安全性”。