智能指针的线程安全

参考

  1. 为什么多线程读写 shared_ptr 要加锁?
  2. boost官方文档 shared_ptr_thread_safety

1. 概述

智能指针包括一个实际数据指针和一个引用计数指针,这两个操作不是一个指令可以完成的,因此多线程环境下,势必有问题。


智能指针结构体

2. shared_ptr 的线程安全

2.1. shared_ptr 的线程安全结论

根据boost官方文档 shared_ptr_thread_safety有如下结论:

  1. 同一个shared_ptr被多个线程读,是线程安全的;
  2. 同一个shared_ptr被多个线程写,不是线程安全的;
  3. 共享引用计数的不同的shared_ptr被多个线程写,是线程安全的。

Examples:
shared_ptr p(new int(42));
Code Example 4. Reading a shared_ptr from two threads,线程安全

// thread A
shared_ptr p2(p); // reads p

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

Code Example 5. Writing different shared_ptr instances from two threads,线程安全

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

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

Code Example 6. Reading and writing a shared_ptr from two threads,线程不安全

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

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

Code Example 7. Reading and destroying a shared_ptr from two threads,线程不安全

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

// thread B
// p2 goes out of scope: undefined, the destructor is considered a "write access"

Code Example 8. Writing a shared_ptr from two threads,线程不安全

// thread A
p3.reset(new int(1));

// thread B
p3.reset(new int(2)); // undefined, multiple writes

2.2. shared_ptr 多线程下可能出现的race condition

参考为什么多线程读写 shared_ptr 要加锁?,假设一个shared_ptr的复制分两个步骤:

  1. 复制ptr 指针
  2. 复制引用计数指针

考虑一个简单的场景,有 3 个 shared_ptr 对象 x、g、n:

shared_ptr g(new Foo); // 线程之间共享的 shared_ptr
shared_ptr x; // 线程 A 的局部变量
shared_ptr n(new Foo); // 线程 B 的局部变量

一开始,各安其事。


线程 A 执行x = g;(即 read g),以下完成了步骤 1,还没来及执行步骤 2。这时切换到了 B 线程。

同时线程 B 执行 g = n; (即 write G),两个步骤一起完成了。


这时 Foo1 对象已经销毁,x.ptr 成了空悬指针!
最后回到线程 A,完成步骤 2:

多线程无保护地读写 g,造成了“x 是空悬指针”的后果。这正是多线程读写同一个 shared_ptr 必须加锁的原因。

3. weak_ptr

weak_ptr最初的引入,是为了解决shared_ptr互相引用导致的内存无法释放的问题。weak_ptr不会增加引用计数,不能直接操作对象的内存(需要先调用lock接口),需要和shared_ptr配套使用。

同时,通过weak_ptr获得的shared_ptr可以安全使用,因为其lock接口是原子性的,那么lock返回的是一个新的shared_ptr,不存在同一个shared_ptr的读写操作,除非后续又对这个新的shared_ptr又被其他线程同时读写。

你可能感兴趣的:(智能指针的线程安全)