簡體   English   中英

具有 memory_order_relaxed 的存儲是否可能永遠不會到達其他線程?

[英]Is it possible that a store with memory_order_relaxed never reaches other threads?

假設我有一個線程A寫入一個atomic_int x = 0; , 使用x.store(1, std::memory_order_relaxed); . 如果沒有任何其他同步方法,使用x.load(std::memory_order_relaxed);其他線程需要多長時間才能看到這一點x.load(std::memory_order_relaxed); ? 鑒於標准給出的 C/C++ 內存模型的當前定義,寫入x的值是否可能完全保持線程本地?

我手頭的實際情況是線程B經常讀取atomic_bool以檢查它是否必須退出; 另一個線程在某個時候向這個 bool 寫入true ,然后在線程 B 上調用 join()。顯然我不介意在線程 B 甚至可以看到 atomic_bool 被設置之前調用 join(),我也不介意線程何時在我調用 join() 之前,B 已經看到了變化並退出了執行。 但我想知道:在雙方都使用memory_order_relaxed ,是否可以調用 join() 並“永遠”阻止,因為更改永遠不會傳播到線程 B?

編輯

我聯系了 Mark Ba​​tty(在數學上驗證並隨后修復 C++ 內存模型要求背后的大腦)。 本來是關於別的(后來證明是 cppmem 和他的論文中的一個已知錯誤;所以幸運的是我沒有完全自欺欺人,也借此機會問他這個問題;他的回答是:

Q:理論上可以這樣的存儲[memory_order_relaxed without (any following) release operation]永遠不會到達其他線程嗎?
馬克:理論上,是的,但我認為沒有觀察到。
問:換句話說,除非你將它們與一些釋放操作(並在另一個線程上獲取)結合起來,假設你想讓另一個線程看到它,否則寬松存儲沒有任何意義嗎?
馬克:他們的幾乎所有用例都使用發布和獲取,是的。

這就是標准對此事的全部看法,我相信:

[intro.multithread]/25實現應確保原子或同步操作分配的最后一個值(按修改順序)在有限的時間內對所有其他線程可見。

在實踐中

如果沒有任何其他同步方法,使用x.load(std::memory_order_relaxed);其他線程需要多長時間才能看到這一點x.load(std::memory_order_relaxed); ?

沒時間。 這是一個正常的寫入,它進入存儲緩沖區,因此它將在不到眨眼的時間內在 L1d 緩存中可用。 但這只是運行匯編指令

指令可以由編譯器重新排序,但沒有一個合理的編譯器會在任意長的循環上重新排序原子操作。

理論上

Q:理論上這樣的存儲[ memory_order_relaxed without (any following) release operation]永遠不會到達其他線程嗎?

馬克:理論上,是的,

你應該問他如果重新添加“后續發布欄”會發生什么。 或者用原子存儲釋放操作。

為什么不將這些重新排序並延遲很長時間? (久到在實踐中似乎是永恆的)

鑒於標准給出的 C/C++ 內存模型的當前定義,寫入 x 的值是否可能完全保持線程本地?

如果一個虛構的、特別反常的實現想要延遲原子操作的可見性,為什么它只對寬松的操作這樣做呢? 它可以很好地完成所有原子操作。

或者永遠不要運行某些線程。

或者運行某些線程的速度太慢,以至於您會認為它們沒有運行。

這是標准在 29.3.12 中所說的:

實現應該在合理的時間內使原子存儲對原子負載可見。

不能保證一個store會在另一個線程中可見,沒有保證的時間,也沒有與內存順序的正式關系。

當然,在每個常規架構上, store變得可見,但在不支持緩存一致性的罕見平台上,它可能永遠不會對load可見。
在這種情況下,您將不得不執行原子讀-修改-寫操作以獲取修改順序中的最新值。

暫無
暫無

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

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