2013-01-12 24 views
3

std::shared_ptr需要在保存引用計數的堆上分配一個控制塊。我從http://ootips.org/yonat/4dev/smart-pointers.html瞭解到另一種方法,它將所有引用保存在雙向鏈表中。它不需要額外的分配和計數器,但參考對象本身更大。爲什麼不std :: shared_ptr使用引用鏈接?

是否有基準或任何明確的原因顯示一個實施比其他實施更好?

+0

你剛纔列出了爲什麼一個人可能比另一個好的明確理由。 –

+0

你確定shared_ptr不能用引用鏈接實現嗎?你能爲此提供一個資料來源嗎? – templatetypedef

+0

重新標記爲包含C++ 11,因爲'shared_ptr'之前不在標準中。 –

回答

8

該標準理論上允許使用鏈表,但因爲複製shared_ptr必須是線程安全的,因此使用鏈表實現該鏈接會更困難。該列表需要用互斥鎖保護(或者是無鎖列表,這非常困難),這樣每次shared_ptr被複制或超出範圍時,該列表都可以安全地由多個線程修改。

使用原子類型進行引用計數並對引用計數更新使用原子操作通常更加簡單和高效。

編輯:要回答下面的評論,只使用原子指針來實現鏈表是不夠的。要添加或從列表中刪除一個節點(對應於增加和減少use_count),您需要自動更新兩個指針,以調整添加/刪除之前和之後節點中的鏈接。 std::atomic<T*>允許您以原子方式更新單個指針,但如果需要以原子方式更新兩個此類對象,則不起作用。由於這兩個指針存在於不同的節點中,所以它們並不相鄰,所以即使是四字CAS也無濟於事。

替代品是一個保護整個列表的互斥鎖(顯然對於爭用不利)或每個列表節點的互斥鎖,其中您鎖定涉及任何更新的每個節點的互斥鎖,該互斥鎖使用更多內存並一次最多影響三個節點,即需要鎖定三個互斥鎖。如果您有use_count()小於或等於五,則複製/銷燬任何一個shared_ptr與複製/銷燬共享同一指針所有權的任何其他實例進行競爭。如果大多數更新是針對彼此遠離的非鄰居節點,但可能不是一般情況下,則可能會因較高的使用次數而導致爭用較少。許多程序使用shared_ptr,使用個位數。即使使用次數很高,並且在任何節點上都沒有爭用,您仍然需要鎖定三個互斥鎖並創建/銷燬列表節點(可能需要堆分配)並更新其鄰居節點中的指針,因此原子增量/減量簡單得多,儘管存在原子整數的爭用仍然可能更快。

上次我在委員會反射提到shared_ptr不需要使用參考計數和可以使用列表我得到的答覆:

有誰實際上,鑑於標準識別多線程做現在?

和(參考線程安全性要求):

這是更難使這項工作(有效)的參考鏈接的實現。我甚至不確定這是否可能,儘管可能。

+0

爲什麼原子指針比原子refcounts更難?我想這個列表可以減少共享緩存線的爭用。 (只是扮演魔鬼的擁護者。) – Potatoswatter

+1

你需要自動更新_two_指針以添加或移除列表節點。 –

+0

@Potatoswatter,更多詳細信息已添加到答案 –

相關問題