記憶體模型與原子操作

抽象記憶體模型(abstract memory model)

想像兩個人同時編輯同一份共用文件。如果你只知道每個人各自打了什麼,卻完全不知道這些編輯實際以什麼順序生效,你根本無法推論出最終文字的樣子。記憶體模型就是那本規則書,它精確規定一個執行緒被允許「看見」另一個執行緒寫了什麼、以及看見的順序。沒有這本規則書,多執行緒程式就沒有任何明確意義。

具體而言,語言層級的記憶體模型(C11、C++11 與 Rust 三者本質上共用同一套)定義了抽象機器對共享記憶體的觀點:哪些寫入保證對哪些讀取可見,以及一個正確的程式被允許觀察到哪些操作重排。它刻意保持抽象——它並不說「這跑在 x86 上」或「這用了快取」,而是給你一小套詞彙(原子操作、記憶體順序、happens-before 關係)與一份契約:只要你正確使用這套詞彙,你的程式行為就彷彿相關操作存在某個單一一致的順序。

為什麼非要有它?因為編譯器與中央處理器為了跑得快,都會積極地重排、快取並消除記憶體操作;這些轉換在單執行緒程式中看不見,但只要第二個執行緒觀察同一塊記憶體,它們就會立刻顯現。記憶體模型正是那條精確且可移植的邊界,它說明:這些是最佳化器與硬體仍被要求保留的東西。這個欄位裡其他所有概念——原子操作、屏障、各種順序——都只是這個模型所建構出來的具體機制。

執行緒 A:x = 1; flag = 1; 執行緒 B:while (flag == 0) {}; 讀 x; 若 x、flag 是普通的 int 且不套用記憶體模型規則,模型不保證 B 會看到 x == 1——編譯器與中央處理器都可能讓 flag 的寫入比 x 的寫入更早變得可見。

經典的「訊息傳遞」模式:少了模型的工具,它就是一場資料競爭,因而是未定義行為。

記憶體模型是一份契約,而非對某一台機器的描述;在「我的 x86 筆電上能跑」的程式仍可能違反模型,並在 ARM 上或編譯器升級後壞掉。

又稱
language memory model記憶體一致性模型