在 LWN 看到 一篇好文章 ,討論Linux kernel 中的 ACCESS_ONCE() macro 的用法與意義。文章討論到 multi-thread 程式共用變數所需要注意的一個細節:要使用 volatile 關鍵字去修飾變數以避免編譯器的最佳化造成的問題。 文中以一個在 Linux kernel 的例子來說明,但考慮到這個議題在任何 multi-thread 程式(或任何有 context-switch 的程式中)都會遇到,所以我用簡單的情況來舉例。考慮某個 thread 有如下程式碼片段: for ( ;; ) { ... if ( global_status == ST_MOVE ) { do_something ( ) ; } ... 它會依據 global_status 的值來決定程式流程,而這個變數可能會在另一個 thread function 中被修改(也可能在 signal handler 中被修改),所以每次 loop 時,可能會執行 do_something() 也可能不會執行它。問題在於編譯器的最佳化往往都會作在語言沒有清楚定義的地方。在 C 語言中,由於沒有規定 multi-thread 的共享變數的行為(在 C11 前幾乎對此沒有著墨),所以若 for loop 中沒有對 global_status 任何修改,編譯器有可能將上述 loop 中的判斷整個拿掉: // if global_status is ST_SLEEP for ( ;; ) { ... /* if (global_status == ST_MOVE) { do_something(); }*/ ... 所以一般要避免這種情況發生,都會以 volatile 修飾 globe_status 變數。這時,我們再來看看 ...