記憶體屏障(memory fence / barrier,atomic_thread_fence)
/ fence -> fents /
屏障是一道獨立的排序指令——你放進指令流裡的一個「沒有操作能越過這條線重排」的標記。與原子載入或儲存不同,屏障不讀也不寫任何值;它不觸碰任何位置。它只約束在它「之前」與「之後」的操作彼此之間能如何被編譯器與中央處理器重排。
在 C 你寫 atomic_thread_fence(memory_order order)(C++ 是 std::atomic_thread_fence、Rust 是 std::sync::atomic::fence)。order 標籤決定口味:release 屏障阻止較早的記憶體操作下沉越過它;acquire 屏障阻止較晚的記憶體操作上浮越過它;seq_cst 屏障是雙向的完整屏障。它與原子操作的關鍵差別在於職責分離:用一個 release「儲存」時,排序與發布值是綁在一起的;用一個 release「屏障」加上之後的 relaxed 儲存,你可以只放一次屏障、然後做好幾個便宜的 relaxed 儲存,或為那些本身不在原子上的操作排序。屏障比逐一替每個存取貼標籤更粗粒度,有時也更便宜或更有彈性。
你究竟何時真的需要它?誠實地說,很少——一個 release 儲存配一個 acquire 載入幾乎能更清楚地涵蓋每個情況。屏障值回票價的幾處是:在緊湊迴圈裡把 relaxed 儲存配上一道獨立的 release 屏障、與記憶體映射的裝置暫存器互動、或精確對上某個演算法證明所要求的那道屏障。標準的提醒是:屏障本身跨執行緒什麼也不排序;它只有在透過 happens-before 關係與另一個執行緒的屏障或原子操作配對時才生效,與 release/acquire 一模一樣。
data = 99; atomic_thread_fence(memory_order_release); atomic_store_explicit(&ready, 1, memory_order_relaxed); /* relaxed 儲存,但屏障讓 'data' 排在它之前 */
一道 release 屏障讓便宜的 relaxed 儲存得以發布資料;讀端在它的 relaxed 載入之後需要配一道 acquire 屏障。
屏障本身「不是」原子的,也不讀寫任何值——別把它和某條硬體屏障指令的成本混為一談;而一道孤立的屏障,如同孤立的 release,在另一個執行緒上有東西與它配對之前什麼也不同步。