智能指針的線程安全

參考

  1. 為什么多線程讀寫 shared_ptr 要加鎖?
  2. boost官方文檔 shared_ptr_thread_safety

1. 概述

智能指針包括一個實際數(shù)據(jù)指針和一個引用計數(shù)指針,這兩個操作不是一個指令可以完成的,因此多線程環(huán)境下,勢必有問題。


智能指針結(jié)構(gòu)體

2. shared_ptr 的線程安全

2.1. shared_ptr 的線程安全結(jié)論

根據(jù)boost官方文檔 shared_ptr_thread_safety有如下結(jié)論:

  1. 同一個shared_ptr被多個線程讀,是線程安全的;
  2. 同一個shared_ptr被多個線程寫,不是線程安全的;
  3. 共享引用計數(shù)的不同的shared_ptr被多個線程寫,是線程安全的。

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

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

// thread B
shared_ptr<int> 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 多線程下可能出現(xiàn)的race condition

參考為什么多線程讀寫 shared_ptr 要加鎖?,假設(shè)一個shared_ptr的復(fù)制分兩個步驟:

  1. 復(fù)制ptr 指針
  2. 復(fù)制引用計數(shù)指針

考慮一個簡單的場景,有 3 個 shared_ptr<Foo> 對象 x、g、n:

shared_ptr<Foo> g(new Foo); // 線程之間共享的 shared_ptr
shared_ptr<Foo> x; // 線程 A 的局部變量
shared_ptr<Foo> n(new Foo); // 線程 B 的局部變量

一開始,各安其事。


線程 A 執(zhí)行x = g;(即 read g),以下完成了步驟 1,還沒來及執(zhí)行步驟 2。這時切換到了 B 線程。

同時線程 B 執(zhí)行 g = n; (即 write G),兩個步驟一起完成了。


這時 Foo1 對象已經(jīng)銷毀,x.ptr 成了空懸指針!
最后回到線程 A,完成步驟 2:

多線程無保護(hù)地讀寫 g,造成了“x 是空懸指針”的后果。這正是多線程讀寫同一個 shared_ptr 必須加鎖的原因。

3. weak_ptr

weak_ptr最初的引入,是為了解決shared_ptr互相引用導(dǎo)致的內(nèi)存無法釋放的問題。weak_ptr不會增加引用計數(shù),不能直接操作對象的內(nèi)存(需要先調(diào)用lock接口),需要和shared_ptr配套使用。

同時,通過weak_ptr獲得的shared_ptr可以安全使用,因為其lock接口是原子性的,那么lock返回的是一個新的shared_ptr,不存在同一個shared_ptr的讀寫操作,除非后續(xù)又對這個新的shared_ptr又被其他線程同時讀寫。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容