多线程环境下,调用不同的 shared_ptr 实例的成员函数是不需要额外的同步手段的,即使这些 shared_ptr 管理的是相同的对象。
多线程对于同一个 shared_ptr 实例的读操作(访问)可以保证线程安全;但对于同一个 shared_ptr 实例的写操作(改变一个 shared_ptr 指向的对象)则需要同步,否则会发生 race condition。即 shared_ptr 的引用计数本身是线程安全且无锁的,但 shared_ptr 对象本身的读写则不是,因为 shared_ptr 有两个数据成员,读写操作不能原子化:
-
多个线程可以同时读取一个 shared_ptr 对象;
-
多个线程同时读写一个 shared_ptr 对象,则需要加锁。
以上讨论是 shared_ptr 对象本身的线程安全级别,而非其管理的对象的安全级别,shared_ptr 所管理的对象的并发操作是否为线程安全的,取决于具体所管理的对象,必要时需要使用一些同步手段加以保证。
#### shared_ptr 的数据结构 shared_ptr 是引用计数型智能指针,计数值保存在堆上动态分配的内存中。具体而言,`shared_ptr`包含两个成员,一个是 Foo 类型的指针,指向被管理的对象;一个 ref_count 指针,指向堆上的控制块:


- 步骤 2:复制 ref_count 指针,并递增引用计数(此递增为线程安全的):

多线程读 shared_ptr 是安全的
一个全局的 shared_ptr:
shared_ptr<Foo> global_ptr;
线程 1 到 N 运行:
void threadFunc(){
shared_ptr<Foo> local = global_ptr;
}
以上对于 shared_ptr 变量global
的读取操作是线程安全的。
多线程无保护读写 shared_ptr 可能出现的 race condition
而要写入一个 shared_ptr(即修改一个 shared_ptr 变量),由于涉及到对象的析构,则有可能带来 race condition。
考虑以下场景,有三个 shared_ptr:
shared_ptr<Foo> g(new Foo); // 线程间共享的 shared_ptr 对象
shared_ptr<Foo> x; // 线程 A 的局部变量
shared_ptr<Foo> n(new Foo); // 线程 B 的局部变量
初始状态:




最后回到线程 A,完成步骤 2:

当然 race condition 远不止这一种,其他线程交织有可能造成其他错误。