2016-08-02 115 views
0

我是新的多線程,我試圖簡單地做一些std:列表線程安全。當項目被添加或刪除到列表中時,是否足以執行mutex.lock()和mutex.unlock()?再次,我只是試圖讓他們線程安全。線程安全標準:列表C++

由於

回答

2

注意,C++不限定線程安全,但定義數據爭這是當多個線程訪問相同的對象並且將它們中的至少一個是一個作家時發生的條件。

您可以使用互斥量使std::list<>數據競賽的成員函數免費。你甚至可以用Wrapping C++ Member Function Calls technique by Bjarne Stroustrup來做任何對象。這被稱爲內部鎖定,這意味着對象保持其自己的互斥鎖。

此方法不會使數據競爭自由泄露對對象內部狀態的引用,例如引用,指針和迭代器。例如,當您迭代列表時,您不希望另一個線程通過刪除元素來使您的迭代器失效,因此您必須鎖定互斥鎖直到迭代完成。

此外,在許多有用的場景中,它不僅僅是一個需要自動更改的對象。在這種情況下,你需要一個互斥體來序列化訪問多個對象。

+1

@Slava顯然,泄漏指針,引用和迭代器的成員函數不能做成線程安全的。但是你甚至沒有理解爲什麼,所以你的評論是無用的。 –

+0

OP詢問他是否可以使'std :: list <>'線程安全,幾乎所有對列表中的數據的訪問都需要迭代器(除了正面和背面等微小的情況),所以不能讓'std :: list'線程安全只需在列表方法中鎖定互斥鎖即可。 – Slava

+0

@Slava這取決於使用模式。例如,如果'std :: list <>'用作隊列或堆棧,則只使用'push_back','pop_front','pop_back'。 –

1

一般來說,是的。如果修改或讀取列表的每個線程/路徑在這樣做之前都鎖定相同的互斥鎖,那麼訪問該列表可被認爲是線程安全的。

請注意,如果有人持有迭代器,引用或指向鎖範圍之外的列表項的指針,則需要注意。在這種情況下,你不再安全。

+0

問題是OP想要在列表本身內部保存互斥並使其線程安全。 – Slava

+0

@Slava對我而言並不清楚這個問題的措辭。 –

4

爲了安全起見,您必須保護對列表的所有訪問。雖然從列表中讀取沒有鎖定不會損壞列表,但如果在另一個線程正在讀取列表時修改列表,那麼線程可能會損壞(即崩潰或產生不正確的結果)。

您必須持有您希望內容穩定的整個代碼段的鎖定。這包括任何時候你有活的迭代器到它的內容。使用std::lock_guard可以幫助確保正確管理鎖。只要在任何範圍的開始處創建它的一個實例,它將操縱你的列表,並且在範圍的末尾它將自動解鎖,即使範圍通過異常退出。

+0

其實第二段是錯的。列表迭代器實際上是穩定的。儘管如此,我沒有看到一個微不足道的修改。重寫它可能是最好的。 – MSalters

+0

@MSalters從何種意義上說?如果其他線程可能修改列表,則迭代器可能會失效,或者這些迭代器引用的內容可能會以導致您的代碼中斷的方式進行更改。也許* stable *不是正確的詞,但我認爲這個陳述通常是正確的。 – nate

+0

@MSalters在我的第一段中,只有閱讀線程會變得腐敗,因爲這個例子沒有說明涉及多個不受保護的作家。這來自OP,他聲稱他只會鎖定修改,而不是讀取。 – nate

0

每當一個項目被添加或移除到列表中時,是否足以執行mutex.lock()和mutex.unlock()?

不,您必須同步所有訪問,包括讀取數據。您可以使用讀/寫鎖來優化多個閱讀器的情況,但是您爲更復雜的鎖定付出的代價可能會讓您獲得所有的好處,這取決於特定的情況。

如果問題是「我可以在列表中放置一個互斥體並使其安全嗎?」那麼答案是否定的,你不能。如果你看看std::list接口,你可以看到幾乎任何訪問數據列表保存是通過迭代器完成的,所以使線程安全std::list將需要使這些迭代器線程安全,這是不可行的(即如果迭代器點刪除數據被刪除)。