久久久久久久999_99精品久久精品一区二区爱城_成人欧美一区二区三区在线播放_国产精品日本一区二区不卡视频_国产午夜视频_欧美精品在线观看免费

專注電子技術(shù)學(xué)習(xí)與研究
當(dāng)前位置:單片機(jī)教程網(wǎng) >> MCU設(shè)計實(shí)例 >> 瀏覽文章

volatile與嵌入式程序員千絲萬縷的聯(lián)系

作者:CHEERS   來源:RTOS-CHEERS   點(diǎn)擊數(shù):  更新時間:2014年06月08日   【字體:

       像大家更熟悉的const一樣,volatile是一個類型修飾符(type specifier)。它是被設(shè)計用來修飾被不同線程訪問和修改的變量。如果沒有volatile,基本上會導(dǎo)致這樣的結(jié)果:要么無法編寫多線程程序,要么編譯器失去大量優(yōu)化的機(jī)會。

        一個嵌入式軟件工程師經(jīng)常打交道的有芯片、中斷、RTOS,關(guān)系到整個系統(tǒng)協(xié)調(diào)有序運(yùn)轉(zhuǎn),多線程顧名思義就是多任務(wù),就像一個人吃飯的時候要去用大腦控制手夾食物,然后要張開嘴送進(jìn)食物,最后咀嚼咽食,多道工序嚴(yán)密配合才能吃飯,同樣智能系統(tǒng)的CPU也是一樣,這個過程一個系統(tǒng)要處理實(shí)現(xiàn)一件事,往往需要高效的處理方式,需要多任務(wù)處理,多任務(wù)之間更需要合理的調(diào)度方式,一般都需要嵌入一種操作系統(tǒng),這時候volatile的作用體現(xiàn)出來了,定義為volatile的變量是說這變量可能會被意想不到地改變,這樣,編譯器就不會去假設(shè)這個變量的值了。精確地說就是,優(yōu)化器在用到這個變量時必須每次都小心地在內(nèi)存中重新讀取這個變量的值,而不是使用保存在寄存器里的備份。如果沒有volatile那整個系統(tǒng)將會亂成一鍋粥,根本無法實(shí)現(xiàn)目標(biāo)。

      很多人會問為什么啊,這個關(guān)鍵在于多任務(wù)處理這個事情的時候會共享系統(tǒng)的一些資源,包括一些重要的變量,這就出現(xiàn)了問題,編譯器在編譯程序后都會進(jìn)行優(yōu)化,程序運(yùn)行時本次任務(wù)訪問CPU時調(diào)用一些參數(shù)變量,為提高存取速度,編譯器優(yōu)化時有時會先把變量讀取到一個寄存器中,進(jìn)行緩存;以后再取變量值時,就直接從寄存器中取值;當(dāng)變量值在本線程里改變時,會同時把變量的新值copy到該寄存器中,以便保持一致,當(dāng)變量在因別的線程而改變了值,這個線程中該寄存器的值不會相應(yīng)改變,從而造成應(yīng)用程序以后讀取的值和實(shí)際的變量值不一致,當(dāng)該寄存器在因此線程而改變了值,原內(nèi)存中變量的值不會改變,從而造成應(yīng)用程序讀取的值和實(shí)際的變量值不一致,所以會發(fā)生意想不到的危險,有些人會問,那這個值為什么會變啊,我只想告訴你這是一個嵌入式系統(tǒng),比如說伺服電機(jī)的控制系統(tǒng),采樣得到的轉(zhuǎn)速和位置會不會隨時改變,可能因?yàn)樵谡{(diào)速進(jìn)程中改變,可能在會在制動進(jìn)程中改變,這個系統(tǒng)的處理必須實(shí)時性極強(qiáng),不然不可能實(shí)現(xiàn)高精度控制!

舉一個不太準(zhǔn)確的例子:發(fā)薪資時,會計每次都把員工叫來登記他們的銀行卡號;一次會計為了省事,沒有即時登記,用了以前登記的銀行卡號;剛好一個員工的銀行卡丟了,已掛失該銀行卡號;從而造成該員工領(lǐng)不到工資

員工 -- 原始變量地址

銀行卡號 -- 原始變量在寄存器的備份

另外很多人可能還是對volatile認(rèn)識不清,我想說,用volatile修飾的全局變量,不是因?yàn)楸籿olatile修飾 了就會發(fā)生改變,不修飾就不會改變,這個變量的改變與否是外因引起的,比如像伺服控制中的轉(zhuǎn)速,抑或是PID 調(diào)節(jié)增量,無論這些變量是否被修飾,他都會因?yàn)橥獠吭蜻\(yùn)行一些線程的時候改變,而volatile的作用就是讓它相對性不變,始終在上一個線程執(zhí)行完后讓當(dāng)前執(zhí)行線程調(diào)用這個數(shù)據(jù)的時候,都會小心的從內(nèi)存地址中調(diào)用它最實(shí)時準(zhǔn)確的數(shù)據(jù),保證系統(tǒng)運(yùn)行流暢,而不是去選擇CASH--緩沖寄存器中保留的那個原始備份,若果選擇系統(tǒng)選擇備份文件,可能導(dǎo)致上邊例子中說的“領(lǐng)不到錢”的尷尬,就是用了一個錯誤的數(shù)據(jù)執(zhí)行了任務(wù),如果伺服控制中出現(xiàn)這種情況可能出現(xiàn)電機(jī)不可控場面,后果不堪設(shè)想,所以對于嵌入式軟件人員來說系統(tǒng)的協(xié)調(diào)處理和實(shí)時性必須嚴(yán)格。

這種變量經(jīng)常會出現(xiàn)在:

1). 并行設(shè)備的硬件寄存器

2). 一個中斷服務(wù)子程序中會訪問到的非自動變量(Non-automatic variables)

3). 多線程應(yīng)用中被幾個任務(wù)共享的變量

補(bǔ)充:volatile應(yīng)該解釋為“直接存取原始內(nèi)存地址”比較合適,“易變的”這種解釋簡直有點(diǎn)誤導(dǎo)人;

“易變”是因?yàn)橥庠谝蛩匾鸬模穸嗑程,中斷等,并不是因?yàn)橛胿olatile修飾了的變量就是“易變”了,假如沒有外因,即使用volatile定義,它也不會變化;

volatile關(guān)鍵字是一種類型修飾符,用它聲明的類型變量表示可以被某些編譯器未知的因素更改,比如:操作系統(tǒng)、硬件或者其它線程等。遇到這個關(guān)鍵字聲明的變量,編譯器對訪問該變量的代碼就不再進(jìn)行優(yōu)化,從而可以提供對特殊地址的穩(wěn)定訪問。

這里它與const不同,const一般是對一些變量進(jìn)行保護(hù),它修飾的一些變量一般不讓改變,主要針對是多個程序員在進(jìn)行一個項目的開發(fā)時,各自的工作不同,不同的人為了保證自己這部分功能的絕對可靠,往往需要用const來保護(hù)自己的某些對象,防止別的程序員無意中改變它。

下面給出三個問題:

1). 一個參數(shù)既可以是const還可以是volatile嗎?解釋為什么。

2). 一個指針可以是volatile 嗎?解釋為什么。

3). 下面的函數(shù)被用來計算某個整數(shù)的平方,它能實(shí)現(xiàn)預(yù)期設(shè)計目標(biāo)嗎?如果不能,試回答存在什么問題:

1

2

3

4

int square( volatile int *ptr )

{

    return *ptr * *ptr;

}

下面是答案:

1). 是的。一個例子是只讀的狀態(tài)寄存器。它是volatile因?yàn)樗赡鼙灰庀氩坏降馗淖。它是const因?yàn)槌绦虿粦?yīng)該試圖去修改它。

2). 是的。盡管這并不很常見。一個例子是當(dāng)一個中斷服務(wù)子程序修改一個指向一個buffer的指針時。

3). 這段代碼是個惡作劇。這段代碼的目的是用來返指針*ptr指向值的平方,但是,由于*ptr指向一個volatile型參數(shù),編譯器將產(chǎn)生類似下面的代碼:

1

2

3

4

5

6

7

int square( volatile int *ptr )

{

    int a,b;

    a = *ptr;

    b = *ptr;

    return a * b;

}

由于*ptr的值可能在兩次取值語句之間發(fā)生改變,因此a和b可能是不同的。結(jié)果,這段代碼可能返回的不是你所期望的平方值!正確的代碼如下:

1

2

3

4

5

6

long square( volatile int *ptr )

{

    int a;

    a = *ptr;

    return a * a;

}

同樣在網(wǎng)上看到兩個比較好的例子,說volatile的用法,在這里和大家分享:

 

嵌入式編程中經(jīng)常用到 volatile這個關(guān)鍵字,的用法可以歸結(jié)為以下兩點(diǎn):

 

一:告訴compiler不能做任何優(yōu)化

 

   比如要往某一地址送兩指令: 

   int *ip =...; //設(shè)備地址 

   *ip = 1; //第一個指令 

   *ip = 2; //第二個指令 

   以上程序compiler可能做優(yōu)化而成: 

   int *ip = ...; 

   *ip = 2; 

   結(jié)果第一個指令丟失。如果用volatile, compiler就不允許做任何的優(yōu)化,從而保證程序的原意: 

   volatile int *ip = ...; 

   *ip = 1; 

   *ip = 2; 

   即使你要compiler做優(yōu)化,它也不會把兩次付值語句間化為一。它只能做其它的優(yōu)化。

 

這對device driver程序員很有用。

 

二:表示用volatile定義的變量會在程序外被改變,每次都必須從內(nèi)存中讀取,

 

而不能把他放在cache或寄存器中重復(fù)使用。

 

   如   volatile char a;   

        a=0; 

       while(!a){ 

//do some things;   

       }   

       doother(); 

   如果沒有 volatile doother()不會被執(zhí)行。

 

以上個人見解,有不對的地方,希望各位博友指正,和大家一起進(jìn)步一起探討,謝謝

 

----2014年3月21日14點(diǎn)20

 

----RTOS-CHEERS

 
 
關(guān)閉窗口

相關(guān)文章

主站蜘蛛池模板: 欧美成年人视频在线观看 | 国产视频久久久 | 日韩综合 | 久久99精品久久久久久 | 久久久久久久久久久高潮一区二区 | 最新免费黄色网址 | 亚洲不卡在线观看 | 国产免费xxx | 黄瓜av | 日本三级网站在线观看 | 黄色在线免费播放 | 精品国产乱码久久久久久丨区2区 | 看av网址| 亚洲最色视频 | 在线看av网址| 亚洲国产欧美国产综合一区 | 欧美精品一区二区在线观看 | 欧美高清成人 | 岛国午夜 | 99精品欧美一区二区三区 | 日本韩国电影免费观看 | 久久精品一区二区 | 亚洲日本欧美 | 婷婷午夜天 | 亚洲人精品午夜 | 网络毛片| 中文字幕乱码一区二区三区 | 亚洲一区二区三区在线播放 | 国产98色在线 | 日韩 | 亚洲精品视频免费 | 久久国产一区二区 | 午夜视频免费在线观看 | 伊人春色成人 | 国产自产c区 | 欧美影院 | 亚洲欧美日本在线 | 在线色网址 | 九九久久久 | 99久久精品视频免费 | 亚洲精品视频在线观看免费 | h视频在线免费观看 |