簡體   English   中英

內存柵欄:獲取/加載和釋放/存儲

[英]Memory fences: acquire/load and release/store

我對std::memory_order_acquirestd::memory_order_release的理解如下:

獲取意味着在獲取柵欄之后出現的任何內存訪問都不能重新排序到柵欄之前。

釋放意味着出現釋放柵欄之前的內存訪問不能重新排序到柵欄之后。

我不明白的是為什么特別是在 C++11 原子庫中,獲取柵欄與加載操作相關聯,而釋放柵欄與存儲操作相關聯。

澄清一下,C++11 <atomic>庫使您可以通過兩種方式指定內存柵欄:您可以將柵欄指定為原子操作的額外參數,例如:

x.load(std::memory_order_acquire);

或者您可以使用std::memory_order_relaxed並單獨指定圍欄,例如:

x.load(std::memory_order_relaxed);
std::atomic_thread_fence(std::memory_order_acquire);

我不明白的是,鑒於上述acquire 和release 的定義,為什么C++11 專門將acquireload關聯起來,將releasestore關聯起來? 是的,我已經看過許多示例,它們展示了如何使用帶有釋放/存儲的獲取/加載在線程之間進行同步,但總的來說,獲取柵欄(防止語句后重新排序)和釋放的想法似乎是柵欄(在語句之前防止內存重新排序)與加載和存儲的想法是正交的。

那么,例如,為什么編譯器不讓我說:

x.store(10, std::memory_order_acquire);

我意識到我可以通過使用memory_order_relaxed來完成上述memory_order_relaxed ,然后使用單獨的atomic_thread_fence(memory_order_acquire)語句,但同樣,為什么我不能直接將 store 與memory_order_acquire一起memory_order_acquire

一個可能的用例可能是,如果我想確保某些存儲(例如x = 10 )發生其他可能影響其他線程的其他語句執行之前

假設我寫了一些數據,然后我寫了一個數據現已准備好的指示。 至關重要的是,沒有其他線程看到數據准備好的指示,看不到數據本身的寫入。 因此,先前的寫入不能超過該寫入。

假設我讀到一些數據准備好了。 在看到數據已經准備就緒的讀取之后,我發出的任何讀取都是必要的。 因此后續的讀取不能移動到讀取之后。

因此,當您執行同步寫入時,通常需要確保在查看同步寫入的任何人都可以看到之前執行的所有寫入。 當您進行同步讀取時,通常必須在同步讀取之后執行任何讀取操作。

或者,換句話說,獲取通常是您可以讀取或訪問資源的讀取,並且后續的讀取和寫入不得在它之前移動。 一個版本通常寫着您已完成資源,並且之前的寫入不得移動到它之后。

我認為Jeff Preshing 的這篇文章可以回答您的問題。

std::memory_order_acquire fence僅確保在fence之前的任何加載操作之前沒有重新排序fence之后的所有加載操作,因此memory_order_acquire 無法確保在執行加載之后其他線程的存儲是可見的。 這就是存儲操作不支持memory_order_acquire原因,您可能需要memory_order_seq_cst來實現存儲的獲取。

作為替代方案,您可以說

x.store(10, std::memory_order_releaxed);
x.load(std::memory_order_acquire);  // this introduce a data dependency

確保所有貨物在商店之前沒有重新訂購。 再次,圍欄在這里不起作用。

此外,原子操作中的內存順序可能比內存柵欄便宜,因為它只能確保相對於原子指令的順序,而不是圍欄之前和之后的所有指令。

又見形式化描述解釋的細節。

暫無
暫無

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

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