32

我有一个关于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);
    //...

第一季度

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

我的意思是当Thread_BSetResource()完全时,Thread_A得到一个错误的智能点GetResource()

第二季度

线程安全是什么意思?

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

4

5 回答 5

40

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

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

在我的代码中,shared_ptr's 通常是局部变量或按值传递的参数,所以没有问题。将它们从一个线程转移到另一个我通常使用线程安全队列。

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

于 2009-03-28T16:13:55.377 回答
33

从升压文档

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

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

所以你的使用是不安全的,因为它使用同时读取和写入m_res. boost 文档中的示例 3也说明了这一点。

您应该使用单独的互斥锁来保护对m_resin SetResource/的访问GetResource

于 2009-03-28T08:27:34.170 回答
3

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

“……

线程安全

仅限 C++0x 的功能是:rvalue-ref/move 支持、分配器支持、别名构造函数、make_shared 和 allocate_shared。此外,采用 auto_ptr 参数的构造函数在 C++0x 模式下已弃用。

Boost shared_ptr 文档的线程安全部分说“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

于 2010-12-08T13:45:43.540 回答
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
于 2016-06-13T03:25:20.673 回答
-1

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

于 2010-06-15T02:46:24.970 回答