通过《Modern C++ std::shared_ptr的实现原理》我们看到引用计数和weak计数在链接pthread的情况下都是原子操作,而不链接的情况必是单线程也没有竞争存在。
可以看到shared_ptr本身只读的情况下是线程安全的,但是有两种情况不怎么安全:
- 通过它操作被管理的对象就必须自己上锁以保证没有数据竞争了。
- 同一个shared_ptr对象被多个线程指向或引用,此时这个shared_ptr对象本身成了共享资源,如果存在一个线程修改shared_ptr对象本身(比如调用reset)则不安全。(请参考另一篇分析reset源码的帖子)
本节着重第一种情况,请看下面的程序:
#include <iostream>
#include <memory>
#include <thread>void shared_ptr_example() {std::shared_ptr<int> sharedInt = std::make_shared<int>(42);// Multiple threads increment the shared integerstd::thread t1([&sharedInt]() {for (int i = 0; i < 1000000; ++i) {// Accessing and modifying the shared data(*sharedInt)++;}});std::thread t2([&sharedInt]() {for (int i = 0; i < 1000000; ++i) {// Accessing and modifying the shared data(*sharedInt)++;}});t1.join();t2.join();// Output may vary due to the lack of synchronizationstd::cout << "Final value: " << *sharedInt << std::endl;
}int main() {shared_ptr_example();return 0;
}
在我机器上结果如下:
[mzhai@c++]$ ./a.out
Final value: 1385208
[mzhai@c++]$ ./a.out
Final value: 2000042
[mzhai@c++]$ ./a.out
Final value: 1375690
每次结果都不一样。所以必定存在数据竞争。