【轉】volatile關鍵字。編譯器不最佳化,多線程會改。防止隨時變動的

來源:互聯網
上載者:User

標籤:.com   com   arch   死迴圈   內嵌   插入   儲存空間   取資料   ref   

  來自:http://www.cnblogs.com/yc_sunniwell/archive/2010/07/14/1777432.html

1. 為什麼用volatile?

    C/C++ 中的 volatile 關鍵字和 const 對應,用來修飾變數,通常用於建立語言層級的 memory barrier。這是 BS 在 "The C++ Programming Language" 對 volatile 修飾詞的說明:

A volatile specifier is a hint to a compiler that an object may change its value in ways not specified by the language so that aggressive optimizations must be avoided.

      volatile 關鍵字是一種類型修飾符,用它聲明的類型變數表示可以被某些編譯器未知的因素更改,比如:作業系統、硬體或者其它線程等。遇到這個關鍵字聲明的變數,編譯器對訪問該變數的代碼就不再進行最佳化,從而可以提供對特殊地址的穩定訪問。聲明時文法:int volatile vInt; 當要求使用 volatile 聲明的變數的值的時候,系統總是重新從它所在的記憶體讀取資料,即使它前面的指令剛剛從該處讀取過資料。而且讀取的資料立刻被儲存。例如:

1 volatile int i=10;
2 int a = i;
3 ...
4 // 其他代碼,並未明確告訴編譯器,對 i 進行過操作
5 int b = i;

    volatile 指出 i 是隨時可能發生變化的,每次使用它的時候必須從 i的地址中讀取,因而編譯器產生的彙編代碼會重新從i的地址讀取資料放在 b 中。而最佳化做法是,由於編譯器發現兩次從 i讀資料的代碼之間的代碼沒有對 i 進行過操作,它會自動把上次讀的資料放在 b 中。而不是重新從 i 裡面讀。這樣以來,如果 i是一個寄存器變數或者表示一個連接埠資料就容易出錯,所以說 volatile 可以保證對特殊地址的穩定訪問。注意,在 VC 6 中,一般偵錯模式沒有進行代碼最佳化,所以這個關鍵字的作用看不出來。下面通過插入彙編代碼,測試有無 volatile 關鍵字,對程式最終代碼的影響:

輸入下面的代碼:

01 #include <stdio.h>
02  
03 void main()
04 {
05     int i = 10;
06     int a = i;
07  
08     printf("i = %d", a);
09  
10     // 下面彙編語句的作用就是改變記憶體中 i 的值
11     // 但是又不讓編譯器知道
12     __asm {
13         mov dword ptr [ebp-4], 20h
14     }
15  
16     int b = i;
17     printf("i = %d", b);
18 }

    然後,在 Debug 版本模式運行程式,輸出結果如下:

i = 10
i = 32

    然後,在 Release 版本模式運行程式,輸出結果如下:

i = 10
i = 10

    輸出的結果明顯表明,Release 模式下,編譯器對代碼進行了最佳化,第二次沒有輸出正確的 i 值。下面,我們把 i 的聲明加上 volatile 關鍵字,看看有什麼變化:

01 #include <stdio.h>
02  
03 void main()
04 {
05     volatile int i = 10;
06     int a = i;
07  
08     printf("i = %d", a);
09     __asm {
10         mov dword ptr [ebp-4], 20h
11     }
12  
13     int b = i;
14     printf("i = %d", b);
15 }

    分別在 Debug 和 Release 版本運行程式,輸出都是:

i = 10
i = 32

    這說明這個 volatile 關鍵字發揮了它的作用。其實不只是“內嵌彙編操縱棧”這種方式屬於編譯無法識別的變數改變,另外更多的可能是多線程並發訪問共用變數時,一個線程改變了變數的值,怎樣讓改變後的值對其它線程 visible。一般說來,volatile用在如下的幾個地方: 
1) 中斷服務程式中修改的供其它程式檢測的變數需要加volatile; 
2) 多任務環境下各任務間共用的標誌應該加volatile; 
3) 儲存空間映射的硬體寄存器通常也要加volatile說明,因為每次對它的讀寫都可能由不同意義;

2.volatile 指標

    和 const 修飾詞類似,const 有常量指標和指標常量的說法,volatile 也有相應的概念:

  • 修飾由指標指向的對象、資料是 const 或 volatile 的:

    1 const char* cpch;
    2 volatile char* vpch;

    注意:對於 VC,這個特性實現在 VC 8 之後才是安全的。

  • 指標自身的值——一個代表地址的整數變數,是 const 或 volatile 的:

    1 char* const pchc;
    2 char* volatile pchv;

    注意:(1) 可以把一個非volatile int賦給volatile int,但是不能把非volatile對象賦給一個volatile對象。

          (2) 除了基本類型外,對使用者定義型別也可以用volatile類型進行修飾。
              (3) C++中一個有volatile標識符的類只能訪問它介面的子集,一個由類的實現者控制的子集。使用者只能用const_cast來獲得對類型介面的完全訪問。此外,volatile向const一樣會從類傳遞到它的成員。

3. 多線程下的volatile   

    有些變數是用volatile關鍵字聲明的。當兩個線程都要用到某一個變數且該變數的值會被改變時,應該用volatile聲明,該關鍵字的作用是防止最佳化編譯器把變數從記憶體裝入CPU寄存器中。如果變數被裝入寄存器,那麼兩個線程有可能一個使用記憶體中的變數,一個使用寄存器中的變數,這會造成程式的錯誤執行。volatile的意思是讓編譯器每次操作該變數時一定要從記憶體中真正取出,而不是使用已經存在寄存器中的值,如下: 

  volatile  BOOL  bStop  =  FALSE;  
   (1) 在一個線程中:  
  while(  !bStop  )  {  ...  }  
  bStop  =  FALSE;  
  return;    
   (2) 在另外一個線程中,要終止上面的線程迴圈:  
  bStop  =  TRUE;  
  while(  bStop  );  //等待上面的線程終止,如果bStop不使用volatile申明,那麼這個迴圈將是一個死迴圈,因為bStop已經讀取到了寄存器中,寄存器中bStop的值永遠不會變成FALSE,加上volatile,程式在執行時,每次均從記憶體中讀出bStop的值,就不會死迴圈了。
    這個關鍵字是用來設定某個對象的儲存位置在記憶體中,而不是寄存器中。因為一般的對象編譯器可能會將其的拷貝放在寄存器中用以加快指令的執行速度,例如下段代碼中:  
  ...  
  int  nMyCounter  =  0;  
  for(;  nMyCounter<100;nMyCounter++)  
  {  
  ...  
  }  
  ...  
   在此段代碼中,nMyCounter的拷貝可能存放到某個寄存器中(迴圈中,對nMyCounter的測試及操作總是對此寄存器中的值進行),但是另外又有段代碼執行了這樣的操作:nMyCounter  -=  1;這個操作中,對nMyCounter的改變是對記憶體中的nMyCounter進行操作,於是出現了這樣一個現象:nMyCounter的改變不同步。

【轉】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.