2012-06-05 29 views
13

簡短介紹:我正在研究多線程代碼,我必須在兩個線程之間共享動態分配的對象。爲了讓我的代碼更清潔(並且更少出錯),我想明確地「刪除」每個線程中的對象,這就是爲什麼我想要使用shared_ptr使用shared_ptr的開銷和實現

第一個問題:

我想知道,如果在shared_ptr實施-> operator具有在運行時產生一些額外開銷(例如較大然後unique_ptr)。我所談論的對象通常是在創建之後只複製一次longlife實例(當我在線程之間分配它們時),那麼我只能訪問這些對象的方法和字段。

我知道,那shared_ptr只保護引用計數。

第二個問題:

如何很好的shared_ptr在優化的libstdC++?它總是使用互斥鎖還是利用原子操作(我專注於x86和ARM平臺)?

+3

在'shared_ptr'的好實現中,當通過' - >'解引用指針時,應該有零開銷。我不熟悉libstdC++,所以我無法回答你的第二個問題。儘管如此,你還是有標題的,所以你可以通過看看它是如何實現的。 –

+2

如果代碼是多線程的,GCC的共享指針使用'std :: atomic '或類似的參考計數器;無論這是一個真正的硬件(lockfree)原子取決於編譯器版本 - 我相信這在GCC 4.7.0中得到了改進。 –

+3

由於引用計數的線程安全增量,複製/分配/超出範圍會帶來額外開銷。 'operator->'看起來與舊的'auto_ptr'完全一樣,即可以預計爲零開銷。 – Damon

回答

14

第一個問題:使用operator->

所有我見過有T*就在shared_ptr<T>類的本地緩存,以便場是在棧上的實現,operator->有這樣一個可比使用本地堆棧的成本T*:完全沒有開銷。

第二個問題:互斥/原子能

我期望的libstdC++到(在舊版本)在x86平臺上使用原子能,無論是通過標準的設備或特定的G ++內部函數。我相信升壓的實施已經這樣做了。

但是,我不能評論ARM。

注意:C++ 11引入移動語義,在使用shared_ptr時自然避免了很多副本。

注:閱讀shared_ptrhere關於正確使用,您可以使用引用shared_ptrconst與否),以避免大部分的拷貝/破壞一般,所以這些表現不是太重要。

+0

在回答你附加它據說使用'make_shared'。我不知道如何在構造函數的初始化列表上使用這個模板?例如,類Foo具有字段'shared_ptr num',所以構造函數應該如下所示:'Foo :: Foo(void):num(move(make_shared(new int(30)))){...} ? – Goofy

+2

@Goofy:不,使用'make_shared'你不需要顯式地執行'new',另一方面你需要明確地傳遞創建的對象的類型;也不需要臨時撥打「移動」號碼。因此,它產生:'Foo :: Foo():num(std :: make_shared (30)){}' –

+0

好吧,很棒:)我仍然習慣了C++中的右值;) – Goofy

12

GCC的shared_ptr將在單線程代碼中不使用鎖定或原子。在多線程代碼中,如果CPU支持原子比較和交換指令,它將使用原子操作,否則引用計數將受互斥量保護。在i486及更高版本中,它使用原子,i386不支持cmpxchg,因此使用基於互斥體的實現。我相信ARM在ARMv7架構和以後使用原子。

(這同樣適用於std::shared_ptrstd::tr1::shared_ptr。)

+1

GCC如何知道代碼是/將是多線程的或不是? –

+0

@DrewNoakes - 你必須用#define來告訴它。 –

+0

你有這方面的參考嗎?我做了一些搜索,找不到一個。 –