是否可以同时重置和复制shared_ptr的线程安全?

时间:2014-11-26 13:01:49

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

Boost documentation描述了同时从多个线程访问共享指针时的行为。特别是他们举了一些例子:

shared_ptr<int> p(new int(42));

//--- Example 1 ---

// thread A
shared_ptr<int> p2(p); // reads p

// thread B
shared_ptr<int> p3(p); // OK, multiple reads are safe

//--- Example 2 ---

// thread A
p.reset(new int(1912)); // writes p

// thread B
p2.reset(); // OK, writes p2

//--- Example 3 ---

// thread A
p = p3; // reads p3, writes p

// thread B
p3.reset(); // writes p3; undefined, simultaneous read/write
...

但他们没有说(或者我看不到)如果同时写入和读取相同的shared_ptr对象会发生什么。说:

shared_ptr<int> p(new int(42));

//--- My Example ---

// thread A
p.reset(new int(1912));

// thread B
shared_ptr<int> p1 = p;

所以我的问题是最后一个例子是否合适?

注意:Boost的第三个例子解释了并行读取和写入同一个对象是不安全的。但在他们的示例中,他们将p3分配给p,这是p3的副本。因此,我不清楚该示例的安全性是否取决于p3被分配给其副本或其他内容是否不安全的事实。

2 个答案:

答案 0 :(得分:13)

  

但他们没有说(或者我看不到)如果同时写入和读取相同的shared_ptr对象会发生什么。

是的,他们这样做:

  

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

     

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

(强调我的)

我觉得很清楚。

  

所以我的问题是最后一个例子是否正常?

不,因为您所做的不是从单个实例同时读取,也不是写入单独的实例。您正在同时阅读和编写单个实例。这是一场数据竞赛和未定义的行为。

答案 1 :(得分:1)

现在我们有了C ++ 11(和14/17),你可以使用原子共享指针类来原子地处理线程中的共享指针。

http://en.cppreference.com/w/cpp/memory/shared_ptr/atomic

简单地说,如果你最终可能修改共享指针,你应该在任何地方使用原子函数(所有读取和所有写入。)然后你的线程不会因为共享指针而崩溃。