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
被分配给其副本或其他内容是否不安全的事实。
答案 0 :(得分:13)
但他们没有说(或者我看不到)如果同时写入和读取相同的shared_ptr对象会发生什么。
是的,他们这样做:
shared_ptr
实例可以由多个线程同时“读取”(仅使用const操作访问)。可以通过多个线程同时“写入”(使用诸如shared_ptr
或operator=
之类的可变操作来访问)不同的reset
个实例(即使这些实例是副本,并且共享相同的引用计数的下面。)任何其他同步访问都会导致未定义的行为。
(强调我的)
我觉得很清楚。
所以我的问题是最后一个例子是否正常?
不,因为您所做的不是从单个实例同时读取,也不是写入单独的实例。您正在同时阅读和编写单个实例。这是一场数据竞赛和未定义的行为。
答案 1 :(得分:1)
现在我们有了C ++ 11(和14/17),你可以使用原子共享指针类来原子地处理线程中的共享指针。
http://en.cppreference.com/w/cpp/memory/shared_ptr/atomic
简单地说,如果你最终可能修改共享指针,你应该在任何地方使用原子函数(所有读取和所有写入。)然后你的线程不会因为共享指针而崩溃。