2010-04-21 49 views
6

我有一個線程A分配內存並將其分配給共享指針。然後這個線程產生3個其他線程X,Y和Z,並將共享指針的副本傳遞給每個線程。當X,Y和Z超出範圍時,內存將被釋放。但是有可能2個線程X,Y在相同的時間點超出範圍,並且引用計數存在爭用條件,所以不是將其減少2,而只是減少一次。所以,現在引用計數更新爲0,所以存在內存泄漏。請注意,X,Y和Z只能讀取內存。不寫或重置共享指針。長話短說,參考計數是否會存在競爭條件,從而導致內存泄漏?升壓共享指針:多線程同時讀取訪問

+0

有趣的是,兩個人使用相同的文件來達到相反的結論。 – 2010-04-21 22:53:23

+0

@Mark:我會說文檔不完全清晰(不是說他們錯了,只是他們很容易被誤解)。 – 2010-04-21 23:11:35

+0

我不明白你爲什麼要賞賜你的問題。答案已經存在:) – 2010-04-28 15:56:40

回答

2

其他幾個人已經提供了文件鏈接,說明這是安全的。

對於絕對無可辯駁的證據,請參閱Boost Smartptr實際上是如何在boost/smart_ptr/detail/sp_counted_base_gcc_x86.hpp(或您的平臺的相應文件)中從頭開始實際實現自己的互斥鎖。

6

否,根據the documentation,則不會發生這些問題:

不同shared_ptr實例可以被「寫入」(使用可變操作,例如操作者訪問=或復位)simultaneosly由多個線程(即使當這些實例是拷貝,而且共享下層的引用計數

+0

雖然我有一個問題:依照文檔,混合情況可能會導致undefined beahvior: (...) // ---示例4 --- //線程A p3 = p2; //讀取P2,P3寫入 //線程B // P2超出範圍:不確定,析構函數被認爲是「寫權限」 (...) 不在我們這裏這種情況呢? – Grimmy 2010-04-21 22:40:12

+0

下面的示例顯示,當行爲超出範圍時,行爲顯示爲「未定義」。 – 2010-04-21 22:42:23

+1

@Grimmy,@Brian:在我對文檔中例4的理解中,一個線程試圖讀取另一個線程中的'shared_ptr'變量,而這個變量超出了範圍。這將是未定義的(並且對於其他類型的變量也是未定義的,不僅是'shared_ptr')。如果每個線程都獲得自己的'shared_ptr'變量副本,那麼即使這些變量指向相同的對象(如文檔中的示例2),也可以獨立使用這些變量(並超出範圍)。 – sth 2010-04-21 23:01:19

12

boost::shared_ptr使用鎖(或無鎖的原子訪問),以確保引用計數的原子更新(即使這從文檔頁面不清楚)。如果您通過定義宏BOOST_SP_DISABLE_THREADS來編寫單線程代碼,則可以配置使用鎖。

注意,在http://www.boost.org/doc/libs/1_42_0/libs/smart_ptr/shared_ptr.htm#ThreadSafety文檔的例子是討論與來自不同線程多次寫入的問題正在討論作用於同一shared_ptr情況下,這些線程(在shared_ptr對象可能是在實例全局),而不是不同shared_ptr將複製指向相同的對象,這是shared_ptr的常用用例。你在問題中給出的例子(作用於指向共享對象的副本)是線程安全的。

+0

該評論是完全正確的,但我還要補充說,調用「錯誤」線程的某些對象的析構函數或在「錯誤」時間可以創建常見的多線程錯誤,比如種族和死鎖。 如果被銷燬的對象只釋放內存,這應該不成問題。然而,像系統的其他部分註銷註定的對象一樣的析構函數肯定會導致問題。 – Doug 2010-05-01 09:11:39

+0

@Doug與'shared_ptr'無關,但。最好從鎖定排他性訪問角度考慮,而不是「因爲它在錯誤的時間出現在錯誤的地方而崩潰」。無論解析器訪問什麼資源都應該鎖定自己。 – Potatoswatter 2010-05-01 20:04:10

+0

@Potatoswatter:是的,我明白我提出的問題並不直接與shared_ptr的線程安全性有關。我不認爲競爭條件是「在錯誤的時間出現在錯誤的地方」。我發現了由shared_ptrs導致的錯誤,這些錯誤在非主線程上丟失了最後的引用,並且析構函數在其中進行了非平凡的清理。這與手動刪除指針完全相同 - 「與原始指針相同的線程安全性」正如文檔所述。 – Doug 2010-05-02 01:05:04

1

documentation說:

不同shared_ptr實例可以被「寫入」 simultaneosly由多個線程(即使當這些實例是副本,並且共享(使用可變操作,例如操作者訪問=或復位) )

因此,如果沒有線程訪問其他線程的指針對象,它應該沒問題。請查看文檔中的示例並查看與您的案例相關的示例。

-2

要做的最好的事情是升級到TR1或C++ 0x shared_ptr,而不是Boost變種。我認爲這些標準必須是線程安全的。