C語言中volatilekeyword的作用

來源:互聯網
上載者:User

標籤:style   color   使用   os   io   資料   for   ar   

一.前言

1.編譯器最佳化介紹:

由於記憶體訪問速度遠不及CPU處理速度,為提高機器總體效能,在硬體上引入硬體快速緩衝Cache,加速對記憶體的訪問。另外在現代CPU中指令的運行並不一定嚴格依照順序運行,沒有相關性的指令能夠亂序運行,以充分利用CPU的指令流水線,提高運行速度。以上是硬體層級的最佳化。再看軟體一級的最佳化:一種是在編寫代碼時由程式猿最佳化,還有一種是由編譯器進行最佳化。編譯器最佳化經常使用的方法有:將記憶體變數緩衝到寄存器;調整指令順序充分利用CPU指令流水線,常見的是又一次排序讀寫指令。對常規記憶體進行最佳化的時候,這些最佳化是透明的,並且效率非常好。由編譯器最佳化或者硬體又一次排序引起的問題的解決的方法是在從硬體(或者其他處理器)的角度看必須以特定順序啟動並執行操作之間設定記憶體屏障(memory barrier),linux 提供了一個宏解決編譯器的運行順序問題。

void Barrier(void)

這個函數通知編譯器插入一個記憶體屏障,但對硬體無效,編譯後的代碼會把當前CPU寄存器中的全部改動過的數值存入記憶體,須要這些資料的時候再又一次從記憶體中讀出。

2.volatile總是與最佳化有關,編譯器有一種技術叫做資料流分析,剖析器中的變數在哪裡賦值、在哪裡使用、在哪裡失效,分析結果能夠用於常量合并,常量傳播等最佳化,進一步能夠消除一些代碼。但有時這些最佳化不是程式所須要的,這時能夠用volatilekeyword禁止做這些最佳化。

二.volatile具體解釋:

1.volatile的本意是“易變的” 由於訪問寄存器要比訪問記憶體單元快的多,所以編譯器一般都會作降低存取記憶體的最佳化,但有可能會讀髒資料。當要求使用volatile聲明變數值的時候,系統總是又一次從它所在的記憶體讀取資料,即使它前面的指令剛剛從該處讀取過資料。精確地說就是,遇到這個keyword聲明的變數,編譯器對訪問該變數的代碼就不再進行最佳化,從而能夠提供對特殊地址的穩定訪問;假設不使用valatile,則編譯器將對所聲明的語句進行最佳化。(簡潔的說就是:volatile關鍵詞影響編譯器編譯的結果,用volatile聲明的變數表示該變數隨時可能發生變化,與該變數有關的運算,不要進行編譯最佳化,以免出錯)

2.看兩個案例:

1>告訴compiler不能做不論什麼最佳化

比方要往某一地址送兩指令:
int *ip =...; //裝置地址
*ip = 1; //第一個指令
*ip = 2; //第二個指令
以上程式compiler可能做最佳化而成:
int *ip = ...;
*ip = 2;
結果第一個指令丟失。假設用volatile, compiler就不允許做不論什麼的最佳化,從而保證程式的原意:
volatile int *ip = ...;
*ip = 1;
*ip = 2;
即使你要compiler做最佳化,它也不會把兩次付值語句間化為一。它僅僅能做其他的最佳化。

2>用volatile定義的變數會在程式外被改變,每次都必須從記憶體中讀取,而不能重複使用放在cache或寄存器中的備份。

比如:

volatile char a;

a=0;

while(!a){

//do some things;

}

doother();

假設沒有 volatiledoother()不會被運行

3.以下是使用volatile變數的幾個情境:

1>中斷服務程式中改動的供其他程式檢測的變數須要加volatile;

比如:

static int i=0;

int main(void)

{

     ...

     while (1){

if (i) dosomething();

}

/* Interrupt service routine. */

void ISR_2(void)

{

      i=1;

}

程式的本意是希望ISR_2中斷產生時,在main函數中調用dosomething函數,可是,由於編譯器推斷在main函數裡面沒有改動過i,因此可能僅僅運行一次對從i到某寄存器的讀操作,然後每次if推斷都僅僅使用這個寄存器裡面的“i副本”,導致dosomething永遠也不會被調用。假設將變數加上volatile修飾,則編譯器保證對此變數的讀寫操作都不會被最佳化(肯定運行)。此例中i也應該如此說明。

2>多任務環境下各任務間共用的標誌應該加volatile

3>儲存空間映射的硬體寄存器通常也要加voliate,由於每次對它的讀寫都可能有不允許義。

比如:

假設要對一個裝置進行初始化,此裝置的某一個寄存器為0xff800000。

int  *output = (unsigned  int *)0xff800000;//定義一個IOport;

int   init(void)

{

      int i;

      for(i=0;i< 10;i++){

         *output = i;

}

}

經過編譯器最佳化後,編譯器覺得前面迴圈半天都是廢話,對最後的結果毫無影響,由於終於僅僅是將output這個指標賦值為9,所以編譯器最後給你編譯編譯的代碼結果相當於:

int  init(void)

{

      *output = 9;

}

假設你對此外部裝置進行初始化的過程是必須是像上面代碼一樣順序的對其賦值,顯然最佳化過程並不能達到目的。反之假設你不是對此port重複寫操作,而是重複讀操作,其結果是一樣的,編譯器在最佳化後,或許你的代碼對此地址的讀操作僅僅做了一次。然而從代碼角度看是沒有不論什麼問題的。這時候就該使用volatile通知編譯器這個變數是一個不穩定的,在遇到此變數時候不要最佳化。

比如:

volatile  int *output=(volatile unsigned int *)0xff800000;//定義一個I/Oport

另外,以上這幾種情況經常還要同一時候考慮資料的完整性(相互關聯的幾個標誌讀了一半被打斷了重寫),在1中能夠通過關中斷來實現,2中禁止任務調度,3中則僅僅能依靠硬體的良好設計。

4.幾個問題

 1)一個參數既能夠是const還能夠是volatile嗎?

能夠的,比如僅僅讀的狀態寄存器。它是volatile由於它可能被意想不到地改變。它是const由於程式不應該試圖去改動它。

2) 一個指標能夠是volatile 嗎?

能夠,當一個中服務子程式修該一個指向一個buffer的指標時。

5.volatile的本質:

1> 編譯器的最佳化

在本次線程內, 當讀取一個變數時,為提高存取速度,編譯器最佳化時有時會先把變數讀取到一個寄存器中;以後,再取變數值時,就直接從寄存器中取值;當變數值在本線程裡改變時,會同一時候把變數的新值copy到該寄存器中,以便保持一致。

當變數在因別的線程等而改變了值,該寄存器的值不會對應改變,從而造成應用程式讀取的值和實際的變數值不一致。

當該寄存器在因別的線程等而改變了值,原變數的值不會改變,從而造成應用程式讀取的值和實際的變數值不一致。

2>volatile應該解釋為“直接存取原始記憶體位址”比較合適,“易變的”這樣的解釋簡直有點誤導人。

6.以下的函數有什麼錯誤:

int square(volatile int *ptr)

{

return *ptr * *ptr;

}

該程式的目的是用來返指標*ptr指向值的平方,可是,由於*ptr指向一個volatile型參數,編譯器將產生相似以下的代碼:

int square(volatile int *ptr)

{

int a,b;

a = *ptr;

b = *ptr;

return a * b;

}

由於*ptr的值可能被意想不到地該變,因此a和b可能是不同的。結果,這段代碼可能返不是你所期望的平方值!正確的代碼例如以下:

long square(volatile int *ptr)

{

int a;

a = *ptr;

return a * a;

}

注意:頻繁地使用volatile非常可能會添加?代碼尺寸和降低效能,因此要合理的使用volatile。

 

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.