2013-08-30 29 views
2

我有這個經典問題。我有STL地圖< StudentName,Marks>其中StudentName是字符串,標記是整數。現在STL地圖的高效線程同步技術

,在我的應用程序,多個線程正在訪問這個地圖:

  1. 查找StudentName。如果存在,增加其商標StudentName的
  2. 減少標記
  3. 添加StudentName到地圖
  4. 從地圖中刪除StudentName

問題:什麼是最有效的方法做上述的STL操作多線程環境中的地圖?

當前解決方案: 在地圖上執行所有這些操作的代碼放在臨界區域內。但這是性能下降。 (?舉例來說,如果一個線程是添加標記特定的學生,爲什麼誰想要添加標記爲不同的學生其他線程需要等待)

這是我認爲可以做: 我收集關於SO上其他類似問題/答案在地圖上多線程的信息,這裏是我認爲我需要做的。提供STL的地圖都不是線程安全的,(即當正在更新它沒有其他線程應該訪問地圖)

  1. 我想把只有最後兩個(添加/刪除StudentName)活動的獨家(沒有其他活動應該做的事在並行而添加/刪除從地圖元素/)
  2. 不允許多個線程訪問地圖的相同元素(這樣,多線程不能試圖增加同學生/減少標誌同時)

但我不知道我怎麼能做到這一點(可以使用什麼線程同步對象/技術)我正在通過VS2010在Windows上開發此應用程序

這裏有任何建議或替代方法嗎?

更新: 感謝大家的意見。不幸的是,在VS2010中沒有可用的原子整數。所以,這是我打算根據你的意見做的事情。我有三種鎖: 上圖:map_read_lock,map_write_lock 上的元素:element_write_lock (對於每個元素)

現在,

當在地圖中尋找元素:獲取map_read_lock (這將請允許我同時認定)

當添加/刪除元素映射:獲取map_write_lock (這將防止容器的併發更新,我相信,不推薦)

當更改值時:Get(map_read_lock & element_write_lock)(這將允許並行更改爲不同的值,但會阻止同時更改爲相同的值。此外,將防止容器更新時的值更改,反之亦然)

請建議這聽起來不錯。

+0

使用互斥鎖,即boost :: mutex和scope_lock。最重要的鎖只有當你必須和只是一段時間。例如,當您將元素插入到地圖中並獲取值時。就這樣。順便說一句,考慮使用hashmap即std :: unordered_map - 在某些情況下它更有效。 – LukeCodeBaker

+0

'提供的STL映射不是線程安全的(即沒有其他線程應該在更新時訪問映射)'不完全,我已經在這裏回答了類似的問題http://stackoverflow.com/questions/16130494/are- stdmap-and-stdvector-thread-safe/16130513#16130513如果您不修改映射本身,則可以訪問它的讀寫元素,前提是沒有給定元素的競爭條件。 – alexrider

+0

@LukeCodeBaker他需要以某種方式同步他所有的操作。 –

回答

2

當一個線程增加學生A的標記 而另一個線程刪除學生A時會發生什麼?即使只是修改標記,您也需要在地圖上鎖定 。或者你需要更復雜的交易管理(這可能不是 合理的這樣一個簡單的情況)。

或者,您可以在地圖上使用rwlock,並在地圖中的每個元素上使用獨有的 鎖定。要修改標記,你需要在地圖上讀取一個鎖,並在該元素上設置一個獨佔鎖;到 添加或刪除學生,您在地圖上寫入鎖定。但是 這需要大量的額外資源。

+0

如果學生被引用計數,「刪除」只是「從地圖上刪除」(取決於實際釋放數據的引用計數),那麼修改標記時是否仍需要鎖定地圖? –

+0

@WangderingLogic如何才能將學生引用統計?它們存在於地圖中。 –

+0

我們即將爲每個「Marks」類型的對象添加一個互斥鎖。所以我假設我們可以同時將'Marks'作爲一個結構體的智能ptr。 (或者,我猜是因爲Marks目前只是一個整數,所以我們可以將它變成'std :: atomic_int',然後在地圖上使用'rwlock')。 –

0
  • 第一個問題:學生應該怎麼高效?
  • 第二個問題:多線程真的需要嗎?如果是爲了效率,也許它甚至沒有幫助。

之後,您可以考慮Reader/Writer lock,其中讀卡器鎖不是排他性的。但要小心,因爲實際的評分是寫作的,所以你可能需要爲每個學生另外鎖定以避免爭用。

+0

學生人數會非常高(20k或更多),並且用於決定增加/減少分數的輸入來自不同的來源。因此,多線程。 – Atul

0
  1. 我想把只有最後兩個(添加/刪除StudentName)活動的獨家(沒有其他活動應以並行方式執行,同時添加/從地圖中刪除元素/)

爲此,您需要在地圖上設置讀寫器鎖定。

  • 添加/刪除需要獨佔訪問(寫入器)
  • 訪問學生需要(僅)共享訪問(讀取器)
  1. 不要允許多個線程訪問的相同的元件地圖(以便多個線程不能嘗試同時增加/減少同一學生的標記)

這也是相對簡單的:地圖的每個元素都應該有自己的鎖。以這種方式,訪問元件時不修改映射結構可以只是:

  • 鎖定在共享訪問地圖
  • 鎖定各個元素(即,每個元件都需要自己的鎖)

並因此並行地訪問多個單獨的元素。

在您的特殊情況下,您還可以查看std::atomic。當一個簡單的atomic可以做你想做的事時,不需要去使用鎖。

+0

std :: atomic會幫助增加/減少標記,但是如果另一個線程刪除了map元素呢?猜猜我們仍然需要鎖?如果錯了,PLZ糾正我。 – Atul

+0

@Andrew:這就是爲什麼讀者/寫作者鎖定在地圖上的原因。要增加/減少鎖定(讀取模式),並因此排除地圖本身上的任何添加/刪除操作。 –