前幾天剛好逛到幾篇說明 volatile 的文章,其中有關 volatile 在多執行緒環境的應用並不很完整,這裡做一點補充。

簡單來說,volatile 的作用僅僅是告訴編譯器不要用暫存器快取變數,每次使用都必須從資料的原始來源重新載入。

然而C語言並沒有規定 volatile 應該具備操作原子性,因此光使用 volatile 仍無助於解除 race condition

以下面這段程式碼為例:

volatile int x = 0;

// in thread
x = x + 10;

在沒有 volatile 的情況下,編譯器會自動分析變數 x 的使用情形,只要條件許可,x 有機會在暫存器中歷經很長一段操作(例如一整個迴圈),中途不會重新讀取,也可能不會寫回。

而加了 volatile,只不過是每次使用都必須由記憶體重新存取而已。概念上機器指令會類似下面這樣,這裡假設 R1、R2 代表獨立的暫存器。

thread 1thread 2
R1 <- x
R1 <- R1 + 10
x <- R1
R2 <- x
R2 <- R2 + 10
x <- R2

很明顯的,最後操作的結果仍舊取決於執行順序。有可能 thread 1 和 thread 2 同時取得 x,各自加上 10 並相繼寫回,那麼最後 x 只被加一次 10。也有可能 thread 2 所有操作都發生在 thread 1 寫回之後,那麼 x 會被加兩次 10。

無論如何,遇到 race condition 還是得配合真正的多緒存取控管機制,只使用 volatile 是不夠的。

novus 發表在 痞客邦 PIXNET 留言(0) 人氣()