对于多线程来说,shared_ptr 销毁安全吗?

Chr*_*ger 5 c++ multithreading shared-ptr

我有两个与此类似的课程:

class Foo {
 public:
  void bar() {
    std::lock_guard<std::mutex> lock(m_mutex);
    m_data.push_back('x');
  }
 private:
  std::string m_data;
  std::mutex m_mutex;
};

class Pool {
 public:
   static std::shared_ptr<Foo> Create(int index) {
     std::lock_guard<std::mutex> lock(m_mutex);
     if (m_pool.size() > 10) {
       m_pool.erase(m_pool.begin());
     }
     std::shared_ptr<Foo>& ptr = m_pool[index];
     if (!ptr) ptr.reset(new Foo);
     return ptr;
   }
 private:
   static std::mutex m_mutex;
   static std::map<int, std::shared_ptr<Foo>> m_pool;
};
Run Code Online (Sandbox Code Playgroud)

和几个运行此代码的线程:

void parallel_function(int index) {
  // several threads can get the same index
  std::shared_ptr<Foo> foo = Pool::Create(index);
  foo->bar();
}
Run Code Online (Sandbox Code Playgroud)

Cpreference

所有成员函数(包括复制构造函数和复制赋值)都可以由共享_ptr 的不同实例上的多个线程调用,而无需额外的同步,即使这些实例是同一对象的副本并共享所有权。如果多个执行线程在没有同步的情况下访问同一个shared_ptr,并且这些访问中的任何一个使用shared_ptr的非常量成员函数,那么就会发生数据竞争;原子函数的shared_ptr重载可用于防止数据竞争。

两个问题:

  1. 由于Pool::Create总是返回 的副本shared_ptr,因此我假设每个副本的复制和销毁shared_ptr都是线程安全的,无论它发生在 中m_pool.erase还是末尾parallel_function。它是否正确?

  2. 我调用shared_ptr::operator->的是const成员函数,该函数Foo::bar是线程安全的。这里有数据竞争吗?

Ros*_*lav 4

总结一下我的评论。

  1. 是的,这是线程安全的,因为您在不同的线程中操作shared_ptrs 的单独副本。这是传递 s 副本实际上是合理的少数情况之一shared_ptr
  2. operator->常量成员。所以基本上只要 Foo::bar 是无竞争的,你的代码就没有问题(现在显然是这样)。