記憶體模型與原子操作
原子操作與原子性(atomic operation / atomicity)
Atomic 源自希臘文「不可切割」之意。原子操作是指:從其他每一個執行緒的角度看,它要嘛整個發生、要嘛完全沒發生——不存在任何一刻能讓另一個執行緒撞見它做到一半。想像一道每推一次只放一個人通過的旋轉柵門:你永遠不可能讓兩個人卡在它轉到一半的中間。
為什麼這需要特別保證?即使是看起來人畜無害的一行 count = count + 1,底層其實是三步:把 count 載入暫存器、加一、再存回去。若兩個執行緒把這三步交錯執行,兩者可能都載入了同一個舊值、都加一、都存回——於是你少算了一次遞增。原子遞增把「載入—加—存回」壓縮成單一不可分割的步驟,硬體拒絕讓它被交錯。原子性就是這種「不可分割」的性質;它本身對於相對於其他變數的「順序」還什麼都沒說(那是記憶體順序才加上的)。
關鍵在於:在真實硬體上,原子性只對「小且自然大小」的值(一個指標、一個 32 或 64 位元整數)且正確對齊時才免費,因為它們剛好放進一個機器字組。更寬或未對齊的物件可能需要隱藏的鎖。而且光有原子性還不足以保證正確:你幾乎總是還需要約束順序、並避開資料競爭規則。原子操作是兩個執行緒同時觸碰同一個非原子位置時,唯一不構成未定義行為的合法手段。
atomic_int counter = 0; 在兩個執行緒中各做:atomic_fetch_add(&counter, 1); 保證最終會到 2。若用普通的 int counter 與 counter++,那是資料競爭,最終可能停在 1。
遺失更新的臭蟲:跨執行緒的非原子讀改寫會悄悄漏掉遞增。
原子性講的是不可分割,而非順序或可見性——一個 relaxed 原子操作是完全原子的,卻幾乎不提供任何順序保證;別以為「原子」就等於「執行緒安全且有序」。
又稱
另見