2013-03-09 38 views
2

我想知道如何安全地使用原子操作來管理共享指針。原來,VC11(Visual Studio 2012)支持C++ 11,因此可以允許在std :: shared_ptr上進行讀/寫比賽。 我想檢查我瞭解的基礎知識,然後問一些關於在VC11 std :: shared_ptr原子操作的實現細節。在VC11中的std :: shared_ptr上的atomic_load/atomic_store - 爲什麼全局螺旋鎖?

std::shared_ptr<A> x, y, z; 
x = std::make_shared<A>(args1); 
y = std::make_shared<A>(args2); 

線程1

std::shared_ptr<A> temp = std::atomic_load(y); 

線程2

std::atomic_store(&y, z); 

沒有原子公司,比賽會潛在地引起temp到結束有損壞狀態,或線程2可以刪除A實例正如線程1試圖複製和加入shared_ptr一樣,這會使它指向一個「殭屍」對象。

我就atomic_load和atomic_store在VC11問題:

我注意到他們使用其對全局變量檢查並設置一個環形鎖。 所以我想知道:爲什麼不在shared_ptr本身的引用計數器的最高位進行測試和設置?這種方式鎖定不同的shared_ptr將不會相互競爭。這是沒有原因嗎?編輯:VS執行atomic_is_lock_free。毫不奇怪,因爲它使用了一切自旋鎖。仍然想知道爲什麼他們不能使用shared_ptr-instance特定的鎖而不是全局鎖。

template <class _Ty> inline 
bool atomic_is_lock_free(const shared_ptr<_Ty> *) 
{ // return true if atomic operations on shared_ptr<_Ty> are lock-free 
    return (false); 
} 
+0

您是否檢查過std :: atomic_is_lock_free(&some_shared_ptr)在您的平臺上是否爲true。 – inf 2013-03-09 11:26:27

+0

我讀了'shared_ptr'在裏面使用原子操作。也許你不需要把它們混合在一起。我對嗎? – deepmax 2013-03-09 11:44:38

+2

shared_ptr使用原子操作來遞增和遞減其使用計數。如果沒有這些原子操作,引用計數器的值甚至可以通過讀取/讀取比賽(即,從相同的shared_ptr分配到本地一個線程的2個線程 - 也可以在某些排序下增加少於2個,如果它不是原子更新,但這並不能解決我在文章中提到的兩種競爭條件;這是一個單獨的問題 – yonil 2013-03-09 11:52:42

回答

2

由於ref計數存儲在shared_ptr的控制塊中,因此無法對shared_ptr的引用計數執行原子測試和設置。當你試圖嘗試你的測試和設置時,另一個線程可能會釋放最後的shared_ptr引用並從你的下面刪除控制塊。

Thread 1         Thread 2 
Read control block address 

              Decrement ref count (now 0) 
              Delete control block 

Test-and-set ref count (undefined behaviour) 

記住,這裏的前提是,多個線程操縱相同 shared_ptr的實例。如果每個線程都有自己的實例(指向相同的受控對象),那麼我們就沒有問題,也不需要原子shared_ptr操作。

+0

您的斷言是錯誤的,只有在您的代碼中存在錯誤時纔是正確的。 兩個線程都訪問shared_ptr,第一個線程正在調用atomic_load。它應該能夠依賴這樣一個事實,即在調用 期間對象的引用計數至少爲1.如果其他線程刪除對象,例如通過調用reset它。但這是一個錯誤,因爲它只允許使用atomic_store或atomic_exchange操作shared_ptr。 – rioki 2017-12-11 22:01:59

+0

如果我的回答不清楚,我很抱歉,但是這是正確的。考慮一下我們有一個全局的shared_ptr,P和兩個線程都在操縱它的情況。線程1嘗試複製(shared_ptr a = P),線程2嘗試替換值(P = b)。這可以導致我所描述的場景。 – 2017-12-13 14:14:30

+0

如果您想要訪問共享shared_ptr,則需要使用互斥鎖或使用atomic_load和atomic_store,否則所有其他操作都會引入競爭條件。 (很好的解釋:https://youtu.be/lkgszkPnV8g?t = 17m13s) – rioki 2017-12-20 00:54:33

1

篡位引用計數的最高位需要將引用計數作爲計數器來處理以忽略該最高位的代碼。也就是說,它會使最常見的用途變慢,以便在不常見的情況下提供較小的速度增加。

+1

另外,Herb Sutter有一個C++(17?)標準設計方案,該文檔還解釋了atomic_shared_ptr現有方法的缺點(http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4162。pdf) - 您所描述的性能考慮是其中一個缺點。 – 2014-12-09 17:45:05

+0

感謝您連接論文,關於這個問題的精彩閱讀。 – yonil 2015-05-29 07:36:46

相關問題