正文
在嵌入式軟件開發(fā)過程中,如果對(duì)volatile不熟,那可以你應(yīng)該是個(gè)"假嵌入式程序員",因?yàn)橐粋€(gè)變量需不需要使用volatile考慮的場(chǎng)景挺多的,如果在某些場(chǎng)景下亂用,會(huì)影響程序運(yùn)行效率,有時(shí)候忘記加甚至?xí)沟贸绦虬l(fā)生異常,那么bug菌今天就大家好好聊聊這個(gè)C語(yǔ)言關(guān)鍵字:
1
傳統(tǒng)定義
volatile直譯為“易變的”,也就是告訴編譯器這個(gè)變量隨時(shí)都可能發(fā)生變化,編譯器你跟我“特殊照顧一下“。
那么編譯器通常會(huì)怎么去處理使用volatile修飾的變量呢?
對(duì)于C變量都是代表著對(duì)應(yīng)的內(nèi)存,讀取使用volatile修飾的變量,會(huì)直接從其所對(duì)應(yīng)的內(nèi)存地址中獲取最新的數(shù)據(jù),否則,編譯器會(huì)對(duì)其訪問進(jìn)行優(yōu)化,比如直接從緩存中讀取副本、或者是從寄存器中讀取副本。
這樣就可能會(huì)導(dǎo)致數(shù)據(jù)更新不一致的問題。
2
最常用的地方
從前面對(duì)volatile的功能描述,我們可以知道volatile最常用于那些與硬件外設(shè)寄存器打交道的地址,這樣確保每次對(duì)寄存器的讀取都是從內(nèi)存中獲取的最新值,比如:
再比如下圖所示,如果我們向地址0x812100地址連續(xù)改變其值:
那么編譯器通常會(huì)將其直接優(yōu)化為第三條操作,并不會(huì)去執(zhí)行前兩條操作,這樣會(huì)造成寫寄存器時(shí)序上的問題。
如果采用volatile去修飾,則三條命令便會(huì)依次執(zhí)行,達(dá)到我們代碼所示三次操作的目的。
3
更復(fù)雜一點(diǎn)的,也是最重要的
其實(shí)對(duì)于volatile所解決的問題用更加專業(yè)的說法可以分為:可見性和有序性。
1、可見性
所謂可見性,通常是在多線程訪問共享數(shù)據(jù)的情況,當(dāng)一個(gè)線程對(duì)共享變量進(jìn)行修改,而其他線程能否立即觀察到這個(gè)修改的性質(zhì)。
在我們目前大部分單核一級(jí)緩存的CPU無需考慮這個(gè)問題,而對(duì)于現(xiàn)場(chǎng)多核多級(jí)緩存處理器,各個(gè)現(xiàn)場(chǎng)都會(huì)維護(hù)著自己的緩存,如果僅僅只是更新到了自己的緩存中那么其他線程是無法立馬感受到這個(gè)修改的,最終導(dǎo)致結(jié)果不一致。
2、有序性
很多時(shí)候也叫作重排序,說白了就是對(duì)執(zhí)行指令進(jìn)行了執(zhí)行順序上的優(yōu)化,以不改變指令運(yùn)行的最終結(jié)果,而改變指令的執(zhí)行順序。
編譯器可以調(diào)整指令,同樣處理器的多級(jí)流水線和亂序執(zhí)行也同樣可以改變指令執(zhí)行順序;甚至為了多級(jí)緩存的高效執(zhí)行,也同樣會(huì)對(duì)內(nèi)存讀寫操作進(jìn)行重排序。
然而這樣的重排序,卻會(huì)對(duì)多線程并發(fā)訪問共享數(shù)據(jù)的過程中產(chǎn)生問題,從而不符合我們編程源碼的預(yù)期執(zhí)行順序。
但對(duì)于volatile只能在一定程度上防止指令重排序,其只能保證單個(gè)變量訪問的有序性,而不能保證整個(gè)程序的有序性,所以這一點(diǎn)是大家尤為要注意的。
所以講了這么多,相信以后大家再開發(fā)中也都會(huì)遇到。
審核編輯:劉清
-
寄存器
+關(guān)注
關(guān)注
31文章
5359瀏覽量
120803 -
C語(yǔ)言
+關(guān)注
關(guān)注
180文章
7614瀏覽量
137249 -
嵌入式軟件
+關(guān)注
關(guān)注
4文章
240瀏覽量
26673 -
volatile
+關(guān)注
關(guān)注
0文章
45瀏覽量
13041
原文標(biāo)題:這個(gè)變量要不要用volatile修飾呢?
文章出處:【微信號(hào):最后一個(gè)bug,微信公眾號(hào):最后一個(gè)bug】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論