欧美亚洲中文,在线国自产视频,欧洲一区在线观看视频,亚洲综合中文字幕在线观看

      1. <dfn id="rfwes"></dfn>
          <object id="rfwes"></object>
        1. 站長(zhǎng)資訊網(wǎng)
          最全最豐富的資訊網(wǎng)站

          C/C++ 中 volatile 關(guān)鍵字詳解


          1、為什么用volatile?

          C/C++ 中的 volatile 關(guān)鍵字和 const 對(duì)應(yīng),用來(lái)修飾變量,通常用于建立語(yǔ)言級(jí)別的 memory barrier。這是 BS 在 “The C++ Programming Language” 對(duì) volatile 修飾詞的說(shuō)明:

          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 關(guān)鍵字是一種類型修飾符,用它聲明的類型變量表示可以被某些編譯器未知的因素更改,比如:操作系統(tǒng)、硬件或者其它線程等。遇到這個(gè)關(guān)鍵字聲明的變量,編譯器對(duì)訪問(wèn)該變量的代碼就不再進(jìn)行優(yōu)化,從而可以提供對(duì)特殊地址的穩(wěn)定訪問(wèn)。聲明時(shí)語(yǔ)法:int volatile vInt; 當(dāng)要求使用 volatile 聲明的變量的值的時(shí)候,系統(tǒng)總是重新從它所在的內(nèi)存讀取數(shù)據(jù),即使它前面的指令剛剛從該處讀取過(guò)數(shù)據(jù)。而且讀取的數(shù)據(jù)立刻被保存。例如:

          volatile int i=10;  int a = i;  ...  // 其他代碼,并未明確告訴編譯器,對(duì) i 進(jìn)行過(guò)操作  int b = i;

          volatile 指出 i 是隨時(shí)可能發(fā)生變化的,每次使用它的時(shí)候必須從 i的地址中讀取,因而編譯器生成的匯編代碼會(huì)重新從i的地址讀取數(shù)據(jù)放在 b 中。而優(yōu)化做法是,由于編譯器發(fā)現(xiàn)兩次從 i讀數(shù)據(jù)的代碼之間的代碼沒(méi)有對(duì) i 進(jìn)行過(guò)操作,它會(huì)自動(dòng)把上次讀的數(shù)據(jù)放在 b 中。而不是重新從 i 里面讀。這樣以來(lái),如果 i是一個(gè)寄存器變量或者表示一個(gè)端口數(shù)據(jù)就容易出錯(cuò),所以說(shuō) volatile 可以保證對(duì)特殊地址的穩(wěn)定訪問(wèn)。注意,在 VC 6 中,一般調(diào)試模式?jīng)]有進(jìn)行代碼優(yōu)化,所以這個(gè)關(guān)鍵字的作用看不出來(lái)。下面通過(guò)插入?yún)R編代碼,測(cè)試有無(wú) volatile 關(guān)鍵字,對(duì)程序最終代碼的影響,輸入下面的代碼:

          實(shí)例

          #include <stdio.h> void main() { int i = 10; int a = i; printf("i = %d", a); // 下面匯編語(yǔ)句的作用就是改變內(nèi)存中 i 的值 // 但是又不讓編譯器知道 __asm { mov dword ptr [ebp4], 20h } int b = i; printf("i = %d", b); }

          然后,在 Debug 版本模式運(yùn)行程序,輸出結(jié)果如下:

          i = 10  i = 32

          然后,在 Release 版本模式運(yùn)行程序,輸出結(jié)果如下:

          i = 10  i = 10

          輸出的結(jié)果明顯表明,Release 模式下,編譯器對(duì)代碼進(jìn)行了優(yōu)化,第二次沒(méi)有輸出正確的 i 值。下面,我們把 i 的聲明加上 volatile 關(guān)鍵字,看看有什么變化:

          實(shí)例

          #include <stdio.h> void main() { volatile int i = 10; int a = i; printf("i = %d", a); __asm { mov dword ptr [ebp4], 20h } int b = i; printf("i = %d", b); }

          分別在 Debug 和 Release 版本運(yùn)行程序,輸出都是:

          i = 10  i = 32

          這說(shuō)明這個(gè) volatile 關(guān)鍵字發(fā)揮了它的作用。其實(shí)不只是內(nèi)嵌匯編操縱棧”這種方式屬于編譯無(wú)法識(shí)別的變量改變,另外更多的可能是多線程并發(fā)訪問(wèn)共享變量時(shí),一個(gè)線程改變了變量的值,怎樣讓改變后的值對(duì)其它線程 visible。一般說(shuō)來(lái),volatile用在如下的幾個(gè)地方:

          • 1) 中斷服務(wù)程序中修改的供其它程序檢測(cè)的變量需要加 volatile;
          • 2) 多任務(wù)環(huán)境下各任務(wù)間共享的標(biāo)志應(yīng)該加 volatile;
          • 3) 存儲(chǔ)器映射的硬件寄存器通常也要加 volatile 說(shuō)明,因?yàn)槊看螌?duì)它的讀寫(xiě)都可能由不同意義;

          2、volatile 指針

          和 const 修飾詞類似,const 有常量指針和指針常量的說(shuō)法,volatile 也有相應(yīng)的概念:

          修飾由指針指向的對(duì)象、數(shù)據(jù)是 const 或 volatile 的:

          const char* cpch;  volatile char* vpch;

          注意:對(duì)于 VC,這個(gè)特性實(shí)現(xiàn)在 VC 8 之后才是安全的。

          指針自身的值——一個(gè)代表地址的整數(shù)變量,是 const 或 volatile 的:

          char* const pchc;  char* volatile pchv;

          注意:

          • (1) 可以把一個(gè)非volatile int賦給volatile int,但是不能把非volatile對(duì)象賦給一個(gè)volatile對(duì)象。
          • (2) 除了基本類型外,對(duì)用戶定義類型也可以用volatile類型進(jìn)行修飾。
          • (3) C++中一個(gè)有volatile標(biāo)識(shí)符的類只能訪問(wèn)它接口的子集,一個(gè)由類的實(shí)現(xiàn)者控制的子集。用戶只能用const_cast來(lái)獲得對(duì)類型接口的完全訪問(wèn)。此外,volatile向const一樣會(huì)從類傳遞到它的成員。

          3、多線程下的volatile

          有些變量是用 volatile 關(guān)鍵字聲明的。當(dāng)兩個(gè)線程都要用到某一個(gè)變量且該變量的值會(huì)被改變時(shí),應(yīng)該用 volatile 聲明,該關(guān)鍵字的作用是防止優(yōu)化編譯器把變量從內(nèi)存裝入 CPU 寄存器中。如果變量被裝入寄存器,那么兩個(gè)線程有可能一個(gè)使用內(nèi)存中的變量,一個(gè)使用寄存器中的變量,這會(huì)造成程序的錯(cuò)誤執(zhí)行。volatile 的意思是讓編譯器每次操作該變量時(shí)一定要從內(nèi)存中真正取出,而不是使用已經(jīng)存在寄存器中的值,如下:

          volatile  BOOL  bStop  =  FALSE;

          (1) 在一個(gè)線程中:

          while(  !bStop  )  {  ...  }    bStop  =  FALSE;    return;    

          (2) 在另外一個(gè)線程中,要終止上面的線程循環(huán):

          bStop  =  TRUE;    while(  bStop  );  //等待上面的線程終止,如果bStop不使用volatile申明,那么這個(gè)循環(huán)將是一個(gè)死循環(huán),因?yàn)閎Stop已經(jīng)讀取到了寄存器中,寄存器中bStop的值永遠(yuǎn)不會(huì)變成FALSE,加上volatile,程序在執(zhí)行時(shí),每次均從內(nèi)存中讀出bStop的值,就不會(huì)死循環(huán)了。

          這個(gè)關(guān)鍵字是用來(lái)設(shè)定某個(gè)對(duì)象的存儲(chǔ)位置在內(nèi)存中,而不是寄存器中。因?yàn)橐话愕膶?duì)象編譯器可能會(huì)將其的拷貝放在寄存器中用以加快指令的執(zhí)行速度,例如下段代碼中:

          ...    int  nMyCounter  =  0;    for(;  nMyCounter<100;nMyCounter++)    {    ...    }    ...

          在此段代碼中,nMyCounter 的拷貝可能存放到某個(gè)寄存器中(循環(huán)中,對(duì) nMyCounter 的測(cè)試及操作總是對(duì)此寄存器中的值進(jìn)行),但是另外又有段代碼執(zhí)行了這樣的操作:nMyCounter -= 1; 這個(gè)操作中,對(duì) nMyCounter 的改變是對(duì)內(nèi)存中的 nMyCounter 進(jìn)行操作,于是出現(xiàn)了這樣一個(gè)現(xiàn)象:nMyCounter 的改變不同步。

          原文地址:https://www.cnblogs.com/yc_sunniwell/archive/2010/07/14/1777432.html

          贊(0)
          分享到: 更多 (0)
          網(wǎng)站地圖   滬ICP備18035694號(hào)-2    滬公網(wǎng)安備31011702889846號(hào)