記憶體模型與原子操作

原子型別(_Atomic / std::atomic)

/ _Atomic -> uh-TOM-ik /

如果說普通變數是一張任何人隨時都能塗寫的紙條,那麼原子型別就是把同一個值放在一個特別的櫃檯後面,只能以一次乾淨的交易交出或收回。它是三種語言讓你「宣告」某個位置將被多個執行緒觸碰的方式,於是編譯器會發出正確的指令,並停止那些在並行下會出錯的最佳化。

在 C11 你寫 _Atomic int x;(或用 <stdatomic.h> 提供的 atomic_int 別名)。在 C++ 你寫 std::atomic<int> x;。在 Rust 你使用 std::sync::atomic 裡的型別,例如 AtomicU32 或 AtomicUsize,透過 load() 與 store() 等方法存取。這些型別上的操作會帶一個 memory_order 引數(在 C/C++ 中預設為最強的 seq_cst),用來指定這次存取相對於其他記憶體的排序有多強。編譯器保證每次 load/store/讀改寫都是原子的,且不會像對普通變數那樣憑空捏造、複製、合併或上提這些存取。

兩點誠實的提醒。第一,原子型別不會自動就是無鎖:請透過 atomic_is_lock_free()(C)或 is_lock_free()(C++)向執行期詢問——大型結構可能是用隱藏的互斥鎖實作的。第二,原子性不會讓周遭的程式自動正確:你仍須刻意選擇順序,而把每個變數都包進 std::atomic 通常比在臨界區間外加一個普通互斥鎖更慢、也並未更正確。原子型別是用來打造鎖與無鎖結構的銳利低階工具,而非什麼魔法般的「執行緒安全變數」。

#include <stdatomic.h> atomic_bool ready = false; atomic_store(&ready, true); /* 發布端執行緒 */ while (!atomic_load(&ready)) { /* 自旋 */ } /* 消費端執行緒 */

把旗標宣告為 _Atomic,讓並行下的載入/儲存合法且有明確定義;此處若用普通的 bool 就是資料競爭。

std::atomic<T> 要求 T 必須可平凡複製;你無法靠包一層就讓任意類別變原子,而一個「原子」的大型結構可能暗地裡上鎖,破壞你以為擁有的無鎖性。

又称
std::atomicRust AtomicU32原子型別