2010-11-17 135 views
7

我有多個線程修改一個stl向量和一個stl列表。
我想避免如果容器爲空需要鎖定STL是否爲空()線程安全?

下面的代碼是線程安全嗎?如果項目是一個列表或地圖呢?

class A 
{ 
    vector<int> items 
    void DoStuff() 
    { 
     if(!items.empty()) 
     { 
      AquireLock(); 
      DoStuffWithItems(); 
      ReleaseLock(); 
     } 
    } 
} 
+0

感謝您的回覆。爲了澄清這個問題: 另一個線程將添加到項目。沒有其他線程將從項目中刪除 - 刪除將只發生在DoStuffWithItems()內部,並且只有一個線程調用DoStuff()。 好吧,如果items.empty()在另一個線程添加到它時返回false。它不好,如果items.empty()導致應用程序崩潰,如果另一個線程添加到它 – 2010-11-17 15:15:53

回答

6

這取決於你所期望的。其他答案是正確的,一般,標準C++容器不是線程安全的,此外,那特別是你的代碼不會阻止另一個線程修改你的調用empty之間的容器和收購鎖(但這件事與vector::empty的線程安全無關)。

因此,爲了避免任何誤解:您的代碼並不保證items將在塊內非空。

但你的代碼仍然是有用的,因爲所有你想要做的是避免多餘的鎖創建。你的代碼不能保證,但它可以可能防止不必要的鎖創建。它不會工作在所有情況下(其他線程仍然可以清空您的支票和鎖之間的容器),但在一些箱子。如果你只想通過省略多餘的鎖來優化,那麼你的代碼就完成了這個目標。

只要確保任何實際的訪問到容器受鎖保護。

順便說一句,上面是嚴格地說未定義行爲:一個STL實現理論上允許修改調用內部mutable成員empty。這將意味着,顯然是無害的(因爲只讀)調用empty可以實際上會導致衝突。不幸的是,你不能依賴於只讀調用與STL容器安全的假設。

但在實踐中,我敢肯定,vector::empty修改任何成員。但已經爲list::empty我不太確定。如果你真的想保證,那麼要麼鎖訪問或不要使用STL容器。

1

STL不是線程安全的,也是空的。如果你想使容器安全必須通過關閉互斥鎖或其他同步

3

有在容器和STL中的算法沒有任何線程安全保證所有的方法。

所以,第

2

不管是否不爲空是線程安全的,你的代碼不會,因爲寫的,實現你的目標。

class A 
{ 
    vector<int> items 
    void DoStuff() 
    { 
     if(!items.empty()) 
     { 
      //Another thread deletes items here. 
      AquireLock(); 
      DoStuffWithItems(); 
      ReleaseLock(); 
     } 
    } 
} 

更好的解決方案是在每次使用items工作時間鎖定(迭代時,得到的項目,增加項目,檢查計數/空虛,等等),從而提供了自己的線程安全。因此,首先獲取鎖,然後然後檢查向量是否爲空。

+0

你的觀點(/ /另一個線程刪除項目在這裏。然而,顯然你可以在獲得鎖後檢查empty()以便確定。 – 2010-11-17 14:43:04

+0

@skwllsp:一個有效的觀點。如果'empty()'是線程安全的,首先檢查空,鎖定,然後重新檢查可以避免不必要的鎖定。 – Brian 2010-11-17 16:03:29

0

因爲它已經回答了,上面的代碼不是線程安全的,鎖定在實際上對容器做任何事情之前是強制性的。 但以下應該比總是鎖定有更好的表現,我想不出一個可能是不安全的原因。 這裏的想法是,鎖定可能是昂貴的,我們正在避免它,只要不是真的需要。

class A 
{ 
    vector<int> items; 
    void DoStuff() 
    { 
     if(!items.empty()) 
     { 
      AquireLock(); 
      if(!items.empty()) 
      { 
       DoStuffWithItems(); 
      } 
      ReleaseLock(); 
     } 
    } 
}