亚洲最大看欧美片,亚洲图揄拍自拍另类图片,欧美精品v国产精品v呦,日本在线精品视频免费

  • 站長(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)鍵字是一種類(lèi)型修飾符,用它聲明的類(lèi)型變量表示可以被某些編譯器未知的因素更改,比如:操作系統(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 修飾詞類(lèi)似,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) 除了基本類(lèi)型外,對(duì)用戶定義類(lèi)型也可以用volatile類(lèi)型進(jìn)行修飾。
    • (3) C++中一個(gè)有volatile標(biāo)識(shí)符的類(lèi)只能訪問(wèn)它接口的子集,一個(gè)由類(lèi)的實(shí)現(xiàn)者控制的子集。用戶只能用const_cast來(lái)獲得對(duì)類(lèi)型接口的完全訪問(wèn)。此外,volatile向const一樣會(huì)從類(lèi)傳遞到它的成員。

    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)