因時間原因還沒有對volatile關鍵字進行總結,先放上幾個不錯的總結博客,以防後續遺忘。
以下幾種情況需要用到volatile關鍵字:
1、並行設備的硬件寄存器(如:狀態寄存器)
存儲器映射的硬件寄存器通常也要加 voliate,因爲每次對它的讀寫都可能有不同意義。
#define GPC1CON *((volatile unsigned int*)0xE0200080)
#define GPC1DAT *((volatile unsigned int*)0xE0200084)
#define GPC1PUD *((volatile unsigned int*)0xE0200088)
2、一箇中斷服務子程序中會訪問到的非自動變量(Non-automatic variables)
由於訪問寄存器的速度要快過RAM,所以編譯器一般都會作減少存取外部RAM的優化,例如:
static int i=0; //i 爲非自動變量
int main(void)
{
...
while (1){
//由於編譯器判斷在 main 函數裏面沒有修改過 i,因此可能只執行一次對從i到某寄存器的讀操作,
//然後每次if判斷都只使用這個寄存器裏面的“i副本”,導致 dosomething 永遠也不會被調用。
if (i) dosomething();
}
}
/* Interrupt service routine. */
void ISR_2(void)
{
i=1;
}
3、多線程應用中被幾個任務共享的變量
當兩個線程都要用到某一個變量且該變量的值會被改變時,應該用 volatile 聲明,該關鍵字的作用是防止優化編譯器把變量從內存裝入CPU寄存器中。如果變量被裝入寄存器,那麼兩個線程有可能一個使用內存中的變量,一個使用寄存器中的變量,這會造成程序的錯誤執行。volatile的意思是讓編譯器每次操作該變量時一定要從內存中真正取出,而不是使用已經存在寄存器中的值。
volatile BOOL bStop = FALSE; //bStop 爲共享全局變量
(1) 在一個線程中:
while( !bStop ) { ... }
bStop = FALSE;
return;
(2) 在另外一個線程中,要終止上面的線程循環:
bStop = TRUE;
while( bStop );
等待上面的線程終止,如果bStop不使用volatile申明,那麼這個循環將是一個死循環,因爲bStop已經讀取到了寄存器中,寄存器中bStop的值永遠不會變成FALSE,加上volatile,程序在執行時,每次均從內存中讀出bStop的值,就不會死循環了。