新聞中心

對Volatile的理解

作者: 時間:2016-11-26 來源:網(wǎng)絡(luò) 收藏
Volatile 字面的意思時易變的,不穩(wěn)定的。

編譯器優(yōu)化代碼時,可能會把經(jīng)常用到的代碼存在Cache里面,然后下一次調(diào)用就直接讀取Cache而不是內(nèi)存,這樣就大大提高了效率。但是問題也隨之而來了。

本文引用地址:http://butianyuan.cn/article/201611/322064.htm

在多線程程序中,如果把一個變量放入Cache后,又有其他線程改變了變量的值,那么本線程是無法知道這個變化的。它可能會直接讀Cache里的數(shù)據(jù)。但是很不幸,Cache里的數(shù)據(jù)已經(jīng)過期了,讀出來的是不合時宜的臟數(shù)據(jù)。這時就會出現(xiàn)bug。也就是說如果它是一個寄存器變量或者表示一個端口數(shù)據(jù)就容易出錯,所以說volatile可以保證對特殊地址的穩(wěn)定訪問。

用Volatile聲明變量可以解決這個問題。用Volatile聲明的變量就相當(dāng)于告訴編譯器,我不要把這個變量寫Cache,因為這個變量是可能發(fā)生改變的。

如果一個變量的值可能會被程序操作之外的其它操作所改變,那么你必需用volatile 聲明。在嵌入式系統(tǒng)中其它操作是:中斷服務(wù)程序的操作、硬件動作的操作等,下面列舉了需要加volatile 聲明的情況。

1、中斷服務(wù)程序中修改的供其它程序檢測的變量需要加volatile;

2、多任務(wù)環(huán)境下各任務(wù)間共享的標(biāo)志應(yīng)該加volatile;

3、存儲器映射的硬件寄存器通常也要加volatile說明,因為每次對它的讀寫都可能由不同意義;

用volatile聲明的變量是不會被編譯器優(yōu)化掉的

例如:

#definePortA( * ( volatile unsignedint * )0x0000 )

這樣 PortA 成為一個地址在0x0000的unsigned int類型變量。這個定義看起來很復(fù)雜,其實它也可以分解成幾個很簡單的部分來看。 ( volatile unsignedint * )是C語言中的強(qiáng)制類型轉(zhuǎn)換,它的作用是把0x0000這個純粹的十六進(jìn)制數(shù)轉(zhuǎn)換成為一個(地址)指針,其中volatile并不是必要的,它只是告訴編譯器,這個值與外界環(huán)境有關(guān),不要對它優(yōu)化。接下來在外面又加了一個*號,就表示0x0000內(nèi)存單元中的內(nèi)容了。經(jīng)過這個宏定義之后,PortA就被可以做為一個普通的變量來操作,所有出現(xiàn)PortA的地方編譯的時候都被替換成( * ( volatile unsignedint * )0x0000 ),外面一層括號是為了保證里面的操作不會因為運算符優(yōu)先級或者其它不可預(yù)測的原因被改變而無法得到預(yù)期的結(jié)果。

PORTA做為一個輸入端口,其值是由外部設(shè)備決定的,由于外部設(shè)備的變化是隨機(jī)的,因此第一次讀取的值和第二次讀取的值很可能不同,所以我們把它聲明為volatile變量。

a = PORTA;

a = PORTA;

由于PORTA是用volatile聲明的變量,編譯器不會把它優(yōu)化成一句,而如果不是volatile聲明的編譯器就會將第二句優(yōu)化掉,從而程序?qū)雎暂斎攵丝诘淖兓?/p>

通常把嵌入式設(shè)備的所有外圍器件寄存器都聲明為volatile的。

這種定義方法適合所有的C編譯器,可移植性好,但PortA并不是一個真正的變量,只是一個宏名,當(dāng)你調(diào)試一個程序的時候,無法在調(diào)試窗口觀察它的值。另外連接器也失去了靈活性,它得防止其它變量跟此變量沖突。


評論


技術(shù)專區(qū)

關(guān)閉