boost shared_ptr <xxx>线程是否安全?</xxx>

时间:2009-03-28 08:21:17

标签: c++ boost thread-safety shared-ptr boost-smart-ptr

我对boost::shared_ptr<T>有疑问。

有很多帖子。

using namespace boost;

class CResource
{
  // xxxxxx
}

class CResourceBase
{
public:
   void SetResource(shared_ptr<CResource> res)
   {
     m_Res = res;
   }

   shared_ptr<CResource> GetResource()
   {
      return m_Res;
   }
private:
   shared_ptr<CResource> m_Res;
}

CResourceBase base;

//----------------------------------------------
// Thread_A:
    while (true)
    {
       //...
       shared_ptr<CResource> nowResource = base.GetResource();
       nowResource.doSomeThing();
       //...
    }

// Thread_B:
    shared_ptr<CResource> nowResource;
    base.SetResource(nowResource);
    //...

Q1

如果 Thread_A 不关心nowResource是最新的,那么这部分代码会有问题吗?

我的意思是当 Thread_B 完全没有SetResource()时, Thread_A 会在GetResource()之前获得错误的智能点?

Q2

线程安全是什么意思?

如果我不关心资源是否最新,shared_ptr<CResource> nowResource会在nowResource被释放后崩溃,还是问题会破坏shared_ptr<CResource>

5 个答案:

答案 0 :(得分:40)

boost::shared_ptr<>提供一定程度的线程安全性。引用计数以线程安全的方式进行操作(除非您将boost配置为禁用线程支持)。

因此,您可以复制shared_ptr,并正确维护ref_count。你不能在多个线程中安全地做的是从多个线程修改实际的shared_ptr对象实例本身(例如从多个线程调用reset())。因此,您的使用不安全 - 您正在修改多个线程中的实际shared_ptr实例 - 您需要拥有自己的保护。

在我的代码中,shared_ptr通常是按值传递的本地或参数,因此没有问题。从一个线程到另一个线程我通常使用线程安全队列。

当然,这些都没有解决访问shared_ptr指向的对象的线程安全问题 - 这也取决于你。

答案 1 :(得分:31)

来自提升documentation

  

shared_ptr个对象提供相同的功能   内置的线程安全级别   类型。一个shared_ptr实例可以   “read”(仅使用const访问)   操作)同时多个   线程。 不同 shared_ptr   实例可以“写入”   (使用可变操作访问   例如operator=或重置)   同时由多个线程   (即使这些实例是副本,   并分享相同的引用计数   的下面。)

     

任何其他同时访问都会导致未定义的行为。

因此,您的使用不安全,因为它使用m_res的同时读写。 boost文档中的示例3 也说明了这一点。

您应该使用单独的mutex来保护m_res / SetResource中对GetResource的访问权限。

答案 2 :(得分:3)

嗯,tr1 :: shared_ptr(基于boost)文档讲述了一个不同的故事,这意味着资源管理是线程安全的,而对资源的访问则不是。

” ...

线程安全

C ++ 0x-only功能包括:rvalue-ref / move support,allocator support,aliasing constructor,make_shared&amp; allocate_shared。此外,采用auto_ptr参数的构造函数在C ++ 0x模式下不推荐使用。

Boost shared_ptr文档的Thread Safety部分说“shared_ptr对象提供与内置类型相同的线程安全级别。”实现必须确保对单独的shared_ptr实例的并发更新是正确的,即使这些实例共享引用计数,例如。

shared_ptr a(新A); shared_ptr b(a);

//线程1 //线程2

a.reset(); b.reset();

动态分配的对象必须被其中一个线程销毁。弱引用使事情变得更有趣。用于实现shared_ptr的共享状态必须对用户透明,并且必须始终保留不变量。共享状态的关键部分是强弱参考计数。对这些线程的更新需要是原子的并且对所有线程都是可见的,以确保正确清理托管资源(毕竟,这是shared_ptr的工作!)在多处理器系统上,可能需要内存同步,以便引用计数更新和销毁托管资源是无竞争的。

...“

http://gcc.gnu.org/onlinedocs/libstdc++/manual/memory.html#std.util.memory.shared_ptr

答案 3 :(得分:1)

m_Res 不是线程安全的,因为它同时读/写, 你需要boost :: atomic_store / load函数来保护它。

//--- Example 3 ---
// thread A
p = p3; // reads p3, writes p
// thread B
p3.reset(); // writes p3; undefined, simultaneous read/write

答案 4 :(得分:-1)

添加,您的类具有循环引用条件; shared_ptr<CResource> m_Res不能是CResourceBase的成员。您可以改为使用weak_ptr