在程式設計中,尤其是在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成員函式;即只能訪問它的接口的子集。
- 只能通過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關係,類似於申請和釋放一個互斥鎖。