C++ shared_ptr的線程安全問題

shared_ptr的線程安全問題

首先看看下面的圖,這個圖描述的就是對象、資源、引用計數之間的關係。
在這裏插入圖片描述

shared_ptr的線程安全問題需要從兩個角度來分析:
(1)從引用計數的角度來看:
雖然引用計數存在於每一個shared_ptr對象中,但是實際上它是要跟隨對象所管理的資源。引用計數會隨着指向這塊資源的shared_ptr對象的增加而增加。因此引用計數是要指向同一塊資源的所有的對象共享的,所以實際上引用計數在shared_ptr底層中是以指針的形式實現的,所有的對象通過指針訪問同一塊空間,從而實現共享。

那麼也就是說,引用計數是一個臨界資源,所以在多線程中,我們必須要保證臨界資源訪問的安全性,因此在shared_ptr底層中在對引用計數進行訪問之前,首先對其加鎖,當訪問完畢之後,在對其進行解鎖。

所以shared_ptr的引用計數是線程安全的。

(2)從被shared_ptr對象所管理的資源來看:
shared_ptr對象所管理的資源存放在堆上,它可以由多個shared_ptr所訪問,所以這也是一個臨界資源。因此當多個線程訪問它時,會出現線程安全的問題

首先shared_ptr對象有兩個變量,一個是指向的對象的指針,還有一個就是我們上面看到的引用計數, 當shared_ptr發生拷貝的時候,是先拷貝智能指針,然後再拷貝引用計數,也就是說,shared_ptr的拷貝並不是一個原子操作。而問題就出現在這裏。

用一個簡單的例子來說明:

假如有下面三個同類型的shared_ptr:
shared_ptr<foo> p1;                 //線程A的局部變量
shared_ptr<foo> p2(new foo);        //線程A和線程B所共享
shared_ptr<foo> p3(new foo);        //線程B的局部變量

(1)一開始他們之間的關係可以用下圖來表示:
在這裏插入圖片描述
(2)然後線程A先執行語句:p1=p2,在執行這條語句時,先改變ptr的指向,然後才修改引用計數。因爲現在是多線程,所以很可能出現這樣的情況:在線程A執行完步驟一時,還沒來得及執行步驟二,就輪到線程B來執行。如下圖所示:
在這裏插入圖片描述
(3)現在線程B開始執行p2=p3,並且沒有被打斷,也就是說步驟一二都完成。
先是步驟一
在這裏插入圖片描述
然後步驟二:
在這裏插入圖片描述
注意此時因爲第一個資源的引用計數已經爲0,所以會銷燬該資源,也就是說,步驟二執行完之後,p1的ptr是一個懸空指針

(4)接下來輪到線程A執行,但是此時線程A是從上一次執行到的地方開始執行,也就是說,線程A會從步驟二開始執行。
在這裏插入圖片描述
所以多個shared_ptr對象對其所管理的資源的訪問不是線程安全的。如果不使用鎖這會造成線程安全問題。

(5)所以當我們多個線程訪問同一個shared_ptr時,應該要進行加鎖操作。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章