嵌入式開發(fā)的小伙伴,尤其是嵌入式底層驅(qū)動開發(fā)的小伙伴,一定見過成片、成片的volatile關(guān)鍵字定義的變量。以stm32官方提供的hal庫為例:
那么,為什么volatile在嵌入式設(shè)計中如此重要?
首先,從volatile的作用說起:
volatile作為關(guān)鍵字,確保被volatile修飾的變量不會被編譯器的“錯誤”優(yōu)化。
一個定義為volatile的變量就是說這個變量可能會被意想不到的改變,這樣,編譯器就不會去隨便假設(shè)并優(yōu)化這個變量的訪問方式。簡單的說,就是告訴編譯器我這個值是會隨時變化的,不要自作聰明的進(jìn)行訪問優(yōu)化了,必須每次重新讀取/訪問這個變量真實(shí)地址的內(nèi)容,而不是使用保存在寄存器里面的備份。
為什么不能優(yōu)化?
一、編譯器無法預(yù)測硬件行為
比如,嵌入式驅(qū)動程序每隔1秒讀取一次某個GPIO的高/低狀態(tài),并打印;假設(shè)該GPIO高/低狀態(tài)寄存器對應(yīng)的地址為0x1000 0000;
1. 不加volatile的程序設(shè)計,示例偽代碼:
針對以上代碼,編譯會"聰明"的認(rèn)為,GPIO_STATUS_REG_READ一直讀的是一個固定地址的內(nèi)容,而且中間又沒有代碼對這個地址的內(nèi)容改寫,為了性能優(yōu)化,編譯器會把while循環(huán)里面對GPIO_STATUS_REG_READ的讀操作優(yōu)化掉,而直接用a變量的值。那么,就會每隔1秒打印1次a變量的值,也就是打印的值會一直不變。
但實(shí)際情況,GPIO_STATUS_REG_READ的值是可能會一直變化的,它取決于當(dāng)前這個GPIO高或低狀態(tài)。而不是被編譯器優(yōu)化后的一直不變;因為編譯器雖然聰明,但它只能知道軟件是否有改寫對應(yīng)地址的內(nèi)容,并無法知道硬件是否會改變當(dāng)前地址對應(yīng)的內(nèi)容。聰明反被聰明誤!
2. 改進(jìn)后,加volatile的程序設(shè)計,示例偽代碼:
改進(jìn)的代碼,GPIO_STATUS_REG_READ 的訪問增加了volatile修飾,那么,編譯器對于GPIO_STATUS_REG_READ 的讀寫代碼就不會自作聰明的進(jìn)行優(yōu)化了,而是,在while循環(huán)里面,每次都規(guī)規(guī)矩矩的去0x1000 0000 這個硬件地址讀取數(shù)據(jù),這樣就可以讀取到真實(shí)的硬件狀態(tài)了。
是不是有點(diǎn)類似 cache 和內(nèi)存的一致性問題?
二、編譯器無法預(yù)測多任務(wù)/多線程
兩個任務(wù)/線程,對同一個全局變量進(jìn)行讀寫操作,并打印當(dāng)前變量的值。
1. 不加volatile的程序設(shè)計,示例偽代碼:
編譯器對于這種情況而言,又要開始耍小聰明了,
它認(rèn)為_Task_Test_A里面每次都是給*g_test_ptr賦值100,那干嘛不優(yōu)化成下面這樣,
對于_Task_Test_B,g_test_var賦值200后,就沒有變化了,編譯器也很"聰明"地進(jìn)行了優(yōu)化,
于是,程序運(yùn)行的結(jié)果就是:
A:100
B:200
A:100
B:200
而實(shí)際情況是,_Task_Test_A已經(jīng)通過指針的方式間接修改了g_test_var 的內(nèi)容,正確的程序運(yùn)行結(jié)果應(yīng)該是:
A:100
B:100
A:100
B:100
2. 加volatile,改進(jìn)一下程序設(shè)計,示例偽代碼:
那么,對于編譯器就不會再自作聰明的對_Task_Test_B 的g_test_var讀取訪問做優(yōu)化了,而是每次規(guī)規(guī)矩矩的從g_test_var的地址讀取真實(shí)的內(nèi)容,那么打印就會變成我們預(yù)期的結(jié)果:
A:100
B:100
A:100
B:100
三、編譯器無法預(yù)測中斷行為
同理編譯器無法預(yù)測多任務(wù)、多線程行為一樣,編譯器也無法預(yù)測中斷的行為,假如把_Task_Test_A換成一個中斷服務(wù)函數(shù),
在不加volatile 的情況下,打印結(jié)果是:
B:200
B:200
B:200
加了volatile的情況,
打印結(jié)果:
B:100
B:100
B:100
特別聲明:以上內(nèi)容(如有圖片或視頻亦包括在內(nèi))為自媒體平臺“網(wǎng)易號”用戶上傳并發(fā)布,本平臺僅提供信息存儲服務(wù)。
Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.