簡體   English   中英

非鎖多線程共享2變量問題

[英]Multithread share 2 variable problem with nonlock

我有一個關於多線程共享變量問題的問題。 這兩個變量是這樣的:

{
    void* a;
    uint64_t b;
}

只有一個線程可以修改這兩個變量,其他線程會頻繁讀取這兩個變量。 我想一次更改 a 和 b,其他線程會一起看到更改(請參閱新值 a 和新值 b)。 因為很多線程會頻繁讀取這兩個變量,所以不想加鎖,想問有沒有辦法結合change a和b操作,讓它像原子操作一樣? 就像使用記憶柵欄一樣,它會起作用嗎? 謝謝!

您正在尋找SeqLock

它非常適合這種用例,尤其是對於不經常更改的數據。 (例如,像一個由定時器中斷更新的時間變量,到處讀取。)

SeqLock 的優勢包括完美的讀取端擴展(讀取器不需要獲得任何緩存行的獨占所有權,它們是真正的只讀而不僅僅是無鎖的),因此任何數量的讀取器都可以隨心所欲地讀取彼此零爭用。 缺點是偶爾重試,如果讀者碰巧在錯誤的時間嘗試閱讀。 這種情況很少見,而且當作者還沒有寫完東西時就不會發生這種情況。

所以讀者並不是完全沒有等待,事實上,如果作者在錯誤的時間睡覺,讀者就會陷入重試,直到它再次醒來! 所以總體而言,該算法甚至不是無鎖或無阻塞的。 但是非常常見的快速路徑只是從與數據相同的高速緩存行中額外讀取兩次,以及讀取器中 LoadLoad 排序所需的任何內容。 如果自上次讀取后沒有寫入,則負載都可能是 L1d 緩存命中。


唯一更好的是,如果您有高效的 16 字節原子存儲和加載,例如帶有 AVX 的 Intel(但還不是 AMD)CPU,如果您的編譯器/libatomic 將它用於std::atomic<struct_16bytes>的 16 字節加載x86-64 lock cmpxchg16b (實際上,盡管大多數 AMD CPU 也具有原子 16 字節加載/存儲,但只有 Intel 正式在其手冊中指出 AVX 功能位意味着對齊 128 位加載/存儲的原子性,例如movaps ,所以編譯器可以安全地開始使用它。)

或者我認為 AArch64 保證 ARMv8.4 中普通stp / ldp的 16 字節原子性。

但是如果沒有這些硬件特性,以及利用它們的編譯器+選項,16 字節加載通常會被實現為原子 RMW,這意味着每個讀取器都擁有緩存行的獨占所有權。 這意味着讀取與其他讀取競爭,而不是緩存線保持共享狀態,在每個正在讀取它的內核的緩存中都是熱的。


就像使用記憶柵欄一樣,它會起作用嗎?

不,內存柵欄不能創建原子性(將多個操作粘合到一個更大的事務中),只能在操作之間創建排序

盡管您可以說 SeqLock 背后的想法是仔細排序寫入和讀取(wrt. to sequence variable),以便檢測撕裂的讀取並在發生時重試。 所以,是的,障礙對此很重要。

暫無
暫無

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

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