簡體   English   中英

C++ map 地圖上的細粒度鎖

[英]Fine-grained locks on C++ map of maps

我有一個 C++17 應用程序,它有多個線程同時寫入地圖的 map:

// global shared variable across threads
std::map<int, std::map<int, int>> the_map;

// many threads inserting different values for varying i and j
auto val = somewhat_expensive_f()
the_map[i][j] = val;

對於此應用程序,完成后,the_map 中有數以萬計的唯一 (i,j) 對和大約 2,000 個 map。 我正在嘗試運行多個線程來運行昂貴的計算,這些計算插入到地圖的 map 中。 現在我正在使用一個不允許並發插入的std::map

我用std::lock_guard<std::mutex>包裝了插入作為第一次切割,當然這確實減慢了應用程序的速度並阻礙了並發性。 我的直覺是,我可以使用一些並發的 map 映射或細粒度鎖定。

對於第二種方法,我的直覺是使用 (i,j) 元組的 hash 進行某種鎖定數組的索引。 例如, lock_guard<mutex>(array_of_locks[hash((i<<32)|j) % array_sz])可以允許在數千個子映射之間共享多個鎖。

問題1:我在正確的軌道上嗎? 對這種方法有任何反饋嗎?

問題 2:使用這種方法,我擔心的一個問題是數組中相鄰互斥體的錯誤共享。 我可以填充它們以填充整個緩存行。 有更好的方法嗎?

我可以考慮的另一種方法是在線程本地映射中進行某種插入,然后稍后在主線程中將它們組合起來。

將您的 map 分成多個地圖,每個地圖都可以獨立鎖定,是一種很好且實用的方法。 有效執行此操作的關鍵是要記住,雖然您的 map 中可能有成千上萬個條目,但您可能沒有那么多線程或那么多內核。

如果你的機器有 8 個內核,那么將你的密鑰散列到 64 個不同的存儲桶中,每個存儲桶都有自己的 map 和互斥鎖,這將確保不會發生爭用,並且不會顯着減慢應用程序的速度。

最多 8 個核心可以同時嘗試插入,即使它們不斷這樣做,它們也只有 12% 的時間會被阻塞。 但是,您的線程可能還有很多其他事情要做,因此真正的爭用遠比這要少得多。

正如@Eric 所指出的,這方面的神奇谷歌詞是“鎖定條帶化”。

關於相鄰互斥體的錯誤共享: std::map插入速度不夠快,不足以成為一個真正的問題。

您可能需要擔心的一件事是用於分配 map 節點的 memory 分配器中的爭用。 畢竟,它們都來自同一個堆。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM