在程式設計中,尤其是在C語言、C++、C#和Java語言中,使用volatile關鍵字聲明的變數或對象通常具有與最佳化、多執行緒相關的特殊屬性。通常,volatile關鍵字用來阻止(偽)編譯器認為的無法“被代碼本身”改變的代碼(變數/對象)進行最佳化。如在C語言中,volatile關鍵字可以用來提醒編譯器它後面所定義的變數隨時有可能改變,因此編譯後的程式每次需要存儲或讀取這個變數的時候,都會直接從變數地址中讀取數據。如果沒有volatile關鍵字,則編譯器可能最佳化讀取和存儲,可能暫時使用暫存器中的值,如果這個變數由別的程式更新了的話,將出現不一致的現象。
在C環境中,volatile關鍵字的真實定義和適用範圍經常被誤解。雖然C++、C#和Java都保留了C中的volatile關鍵字,但在這些程式語言中volatile的用法和語義卻大相逕庭。
基本介紹
- 中文名:Volatile變數
- 語言:C語言,C++,JAVA
- 特點:最佳化、多執行緒相關的特殊屬性
C和C++中的volatile
- 允許訪問記憶體映射設備
- 允許在setjmp和longjmp之間使用變數
- 允許在信號處理函式中使用sig_atomic_t變數
對用戶定義的非基本數據類型使用volatile
- 只能調用volatile成員函式;即只能訪問它的接口的子集。
- 只能通過const_cast運算符轉為沒有volatile修飾的普通對象。即由此可以獲得對類型接口的完全訪問。
- volatile性質會傳遞給它的數據成員。
volatile與多執行緒語義
template <typename T> class LockingPtr{ public: LockingPtr(volatile T& obj, Mutex& mtx) :pObj_(const_cast<T*>(&obj) ), pMtx_(&mtx) { mtx.Lock(); } ~LockingPtr() { pMtx->Unlock(); } T& operator*() { return *pObj_; } T* operator->() { return pObj_; } private: T* pObj_; Mutex* pMtx_; LockingPtr(const LockingPtr&); LockingPtr& operator=(const LockingPtr&);}
C語言中MMIO的例子
static int foo; void bar(void) { foo = 0; while (foo != 255) ;}
void bar_optimized(void) { foo = 0; while (true) ;}
static volatile int foo; void bar (void) { foo = 0; while (foo != 255) ;}
C語言中的最佳化對比
Java中的volatile
- (適用於Java所有版本)讀和寫一個volatile變數有全局的排序。也就是說每個執行緒訪問一個volatile作用域時會在繼續執行之前讀取它的當前值,而不是(可能)使用一個快取的值。(但是並不保證經常讀寫volatile作用域時讀和寫的相對順序,也就是說通常這並不是有用的執行緒構建)。
- (適用於Java5及其之後的版本)volatile的讀和寫建立了一個happens-before關係,類似於申請和釋放一個互斥鎖。