講講volatile的作用

講講volatile的作用
講講volatile的作用
254
推薦
一個定義為volatile的變量是說這變量可能會被意想不到地改變,這樣,編譯器就不會去假設這個變量的值了。精確地說就是,優化器在用到這個變量時必須每次都小心地重新讀取這個變量的值,而不是使用保存在寄存器里的備份。下面是volatile變量的幾個例子:
????1).?并行設備的硬件寄存器(如:狀態寄存器)
????2).?一個中斷服務子程序中會訪問到的非自動變量(Non-automatic?variables)
????3).?多線程應用中被幾個任務共享的變量
????回答不出這個問題的人是不會被雇傭的。我認為這是區分C程序員和嵌入式系統程序員的最基本的問題。嵌入式系統程序員經常同硬件、中斷、RTOS等等打交道,所用這些都要求volatile變量。不懂得volatile內容將會帶來災難。
????假設被面試者正確地回答了這是問題(嗯,懷疑這否會是這樣),我將稍微深究一下,看一下這家伙是不是直正懂得volatile完全的重要性。
????1).?一個參數既可以是const還可以是volatile嗎?解釋為什么。
????2).?一個指針可以是volatile?嗎?解釋為什么。
????3).?下面的函數有什么錯誤:
?????????int?square(volatile?int?*ptr)
?????????{
??????????????return?*ptr?*?*ptr;
?????????}
????下面是答案:
????1).?是的。一個例子是只讀的狀態寄存器。它是volatile因為它可能被意想不到地改變。它是const因為程序不應該試圖去修改它。
????2).?是的。盡管這并不很常見。一個例子是當一個中服務子程序修該一個指向一個buffer的指針時。
????3).?這段代碼的有個惡作劇。這段代碼的目的是用來返指針*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;
?????}
講講我的理解:?(歡迎打板子...~~!)

關鍵在于兩個地方:?????
?
1.?編譯器的優化??(請高手幫我看看下面的理解)

在本次線程內,?當讀取一個變量時,為提高存取速度,編譯器優化時有時會先把變量讀取到一個寄存器中;以后,再取變量值時,就直接從寄存器中取值;

當變量值在本線程里改變時,會同時把變量的新值copy到該寄存器中,以便保持一致

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

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


舉一個不太準確的例子:?

發薪資時,會計每次都把員工叫來登記他們的銀行卡號;一次會計為了省事,沒有即時登記,用了以前登記的銀行卡號;剛好一個員工的銀行卡丟了,已掛失該銀行卡號;從而造成該員工領不到工資?

員工?--?原始變量地址?
銀行卡號?--?原始變量在寄存器的備份?


2.?在什么情況下會出現(如1樓所說)

????1).?并行設備的硬件寄存器(如:狀態寄存器)?
????2).?一個中斷服務子程序中會訪問到的非自動變量(Non-automatic?variables)?
????3).?多線程應用中被幾個任務共享的變量?
????

補充:?volatile應該解釋為“直接存取原始內存地址”比較合適,“易變的”這種解釋簡直有點誤導人;?

“易變”是因為外在因素引起的,象多線程,中斷等,并不是因為用volatile修飾了的變量就是“易變”了,假如沒有外因,即使用volatile定義,它也不會變化;

而用volatile定義之后,其實這個變量就不會因外因而變化了,可以放心使用了;?大家看看前面那種解釋(易變的)是不是在誤導人


------------簡明示例如下:------------------

volatile關鍵字是一種類型修飾符,用它聲明的類型變量表示可以被某些編譯器未知的因素更改,比如:操作系統、硬件或者其它線程等。遇到這個關鍵字聲明的變量,編譯器對訪問該變量的代碼就不再進行優化,從而可以提供對特殊地址的穩定訪問。
使用該關鍵字的例子如下:
int?volatile?nVint;
>>>>當要求使用volatile?聲明的變量的值的時候,系統總是重新從它所在的內存讀取數據,即使它前面的指令剛剛從該處讀取過數據。而且讀取的數據立刻被保存。
例如:
volatile?int?i=10;
int?a?=?i;
...
//其他代碼,并未明確告訴編譯器,對i進行過操作
int?b?=?i;
>>>>volatile?指 出?i是隨時可能發生變化的,每次使用它的時候必須從i的地址中讀取,因而編譯器生成的匯編代碼會重新從i的地址讀取數據放在b中。而優化做法是,由于編 譯器發現兩次從i讀數據的代碼之間的代碼沒有對i進行過操作,它會自動把上次讀的數據放在b中。而不是重新從i里面讀。這樣以來,如果i是一個寄存器變量 或者表示一個端口數據就容易出錯,所以說volatile可以保證對特殊地址的穩定訪問。
>>>>注意,在vc6中,一般調試模式沒有進行代碼優化,所以這個關鍵字的作用看不出來。下面通過插入匯編代碼,測試有無volatile關鍵字,對程序最終代碼的影響:
>>>>首先,用classwizard建一個win32?console工程,插入一個voltest.cpp文件,輸入下面的代碼:
>>
#i nclude?<stdio.h>
void?main()
{
int?i=10;
int?a?=?i;
printf("i=?%d",a);
//下面匯編語句的作用就是改變內存中i的值,但是又不讓編譯器知道
__asm?{
mov?dword?ptr?[ebp-4],?20h
}
int?b?=?i;
printf("i=?%d",b);
}??????
然后,在調試版本模式運行程序,輸出結果如下:
i?=?10
i?=?32
然后,在release版本模式運行程序,輸出結果如下:
i?=?10
i?=?10
輸出的結果明顯表明,release模式下,編譯器對代碼進行了優化,第二次沒有輸出正確的i值。下面,我們把?i的聲明加上volatile關鍵字,看看有什么變化:
#i nclude?<stdio.h>
void?main()
{
volatile?int?i=10;
int?a?=?i;
printf("i=?%d",a);
__asm?{
mov?dword?ptr?[ebp-4],?20h
}
int?b?=?i;
printf("i=?%d",b);
}??????
分別在調試版本和release版本運行程序,輸出都是:
i?=?10
i?=?32
這說明這個關鍵字發揮了它的作用!

------------------------------------


volatile對應的變量可能在你的程序本身不知道的情況下發生改變
比如多線程的程序,共同訪問的內存當中,多個程序都可以操縱這個變量
你自己的程序,是無法判定合適這個變量會發生變化
還比如,他和一個外部設備的某個狀態對應,當外部設備發生操作的時候,通過驅動程序和中斷事件,系統改變了這個變量的數值,而你的程序并不知道。
對于volatile類型的變量,系統每次用到他的時候都是直接從對應的內存當中提取,而不會利用cache當中的原有數值,以適應它的未知何時會發生的變化,系統對這種變量的處理不會做優化——顯然也是因為它的數值隨時都可能變化的情況。

--------------------------------------------------------------------------------

典型的例子
for?(?int?i=0;?i<100000;?i++);
這個語句用來測試空循環的速度的
但是編譯器肯定要把它優化掉,根本就不執行
如果你寫成?
for?(?volatile?int?i=0;?i<100000;?i++);
它就會執行了

volatile的本意是“易變的”?
由于訪問寄存器的速度要快過RAM,所以編譯器一般都會作減少存取外部RAM的優化。比如:

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也應該如此說明。

一般說來,volatile用在如下的幾個地方:

1、中斷服務程序中修改的供其它程序檢測的變量需要加volatile;

2、多任務環境下各任務間共享的標志應該加volatile;

3、存儲器映射的硬件寄存器通常也要加volatile說明,因為每次對它的讀寫都可能由不同意義;

另外,以上這幾種情況經常還要同時考慮數據的完整性(相互關聯的幾個標志讀了一半被打斷了重寫),在1中可以通過關中斷來實
現,2中可以禁止任務調度,3中則只能依靠硬件的良好設計了。
http://blog.21ic.com/user1/2949/archives/2007/35599.html
posted on 2011-11-09 11:11 On the way 閱讀(...) 評論(...) 編輯 收藏

轉載于:https://www.cnblogs.com/areliang/archive/2011/11/09/2242227.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/274883.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/274883.shtml
英文地址,請注明出處:http://en.pswp.cn/news/274883.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

書籍排版學習心得_為什么排版是您可以學習的最佳技能

書籍排版學習心得重點 (Top highlight)I was introduced to design in a serpentine fashion. I don’t have any formal training. Instead, I’ve learned everything through the Web, books, and by interacting with designers daily.我被介紹為蛇形設計。 我沒有任何正規…

javascript專題:如何構建自己的js庫

首先看看這個&#xff1a; (function(){ //運行的代碼 })(); 紅色括號里面是一個匿名函數&#xff0c;紅色括號是分割&#xff0c;表示里面的函數是一個部分&#xff0c;綠色的括號表示一個運算符&#xff0c;表示紅色括號里面的函數要運行。 相當于定義完一個匿名函數后讓它直…

若川的 2021 年度總結,彈指之間

1前言從2014年開始&#xff0c;每一年都會寫年度總結&#xff0c;已經堅持了7個年頭。7年的光陰就是彈指之間&#xff0c;轉瞬即逝。正如孔子所說&#xff1a;逝者如斯夫&#xff0c;不舍晝夜。回顧2014&#xff0c;約定2015&#xff08;QQ空間日志&#xff09;2015年總結&…

線框圖用什么軟件_為什么要在線框中著色?

線框圖用什么軟件I was recently involved in a debate around why some wireframes (which were definitely not UI screens) were not 100% greyscale. This got me thinking — when is it ok to use colour in wireframes, and when is it going to cause you problems fur…

Linux 內核

Linux 內核是一個龐大而復雜的操作系統的核心&#xff0c;不過盡管龐大&#xff0c;但是卻采用子系統和分層的概念很好地進行了組織。通過本專題&#xff0c;我們可以學習 Linux 的分層架構、內核配置和編譯、內核性能調試和 Linux 2.6 中的許多提升功能。Linux 內核組成 Linux…

給asterisk寫app供CLI調用

環境&#xff1a;CentOS6.2 Asterisk 1.8.7.1 一、添加源文件 復制app_verbose.c為app_testApp.c 復制app_verbose.exports為app_testApp.exports 主要是修改一些標識&#xff0c;編譯不會出錯就行&#xff0c;這里列出我進行的主要修改。 1、添加頭文件 #include "aster…

前端,校招,面淘寶,指南

大家好&#xff0c;我是若川。持續組織了6個月源碼共讀活動&#xff0c;感興趣的可以點此加我微信 ruochuan12 參與&#xff0c;每周大家一起學習200行左右的源碼&#xff0c;共同進步。同時極力推薦訂閱我寫的《學習源碼整體架構系列》 包含20余篇源碼文章。歷史面試系列雖然是…

qq空間網頁設計_網頁設計中負空間的有效利用

qq空間網頁設計Written by Alan Smith由艾倫史密斯 ( Alan Smith)撰寫 Negative space is a key design element that you may come across in the fields of art, architecture, interior design, landscaping and web design. Rather than serving as awkward, empty areas …

自定義異常拋法

public List<LogRec> readLogs() throws ReadDataException { try { return returnLogRec(logFileName); } catch(Exception e) { throw new ReadDataException(e); } } 轉載于:https://www.cnblogs.com/zengmiaogen/archive/2012/04/15/2450438.html

SQL SERVER服務停止和啟動命令行

停止服務: net stop mssqlserver 啟動服務: net start mssqlserver 轉載于:https://www.cnblogs.com/davidgu/archive/2010/01/06/1640466.html

Git 和 GitHub 教程——版本控制入門

大家好&#xff0c;我是若川。持續組織了6個月源碼共讀活動&#xff0c;感興趣的可以點此加我微信 ruochuan12 參與&#xff0c;每周大家一起學習200行左右的源碼&#xff0c;共同進步。同時極力推薦訂閱我寫的《學習源碼整體架構系列》 包含20余篇源碼文章。歷史面試系列Learn…

matlab中的:的優先級_內容早期設計:內容優先

matlab中的:的優先級By Simone Ehrlich, Content Strategy Manager由 西蒙埃利希 &#xff0c;內容策略經理 Words are cheap. Cheaper than wires; cheaper than mocks. That doesn’t mean words aren’t important, just less expensive to produce as a design asset. So …

Nunit2.5.10快速上手

1、下載Nunit&#xff1a;http://www.nunit.org/index.php?pdownload&#xff0c;下載MSI格式的安裝包&#xff1b; 2、安裝Nunit&#xff0c;根據提示安裝即可&#xff0c;沒有什么需要配置的&#xff0c;直接下一步就可以了。 3、新建類庫項目NUnitQuickStart&#xff0c;在…

我真的哭了,哭過后呢(-)

這些是山區的孩子們&#xff01; 這是他們的教室。這個也算是&#xff01;如此的師資力量自己解決吃飯問題冬天到了&#xff0c;一起烤烤火與泥土污水一起還好&#xff0c;最大的數字只是10老師抱著孩子來給我們上課了不知道山那邊會是什么呢&#xff1f;又一雙充滿了渴望的大眼…

腦裂問題解決方案_從解決方案到問題

腦裂問題解決方案Once upon a time a couple of years ago, one of my mentors (and favourite people in the world) repeatedly drilled the idea above into my brain. Her advice for Product people was to “fall in love with the problem, not the solution”. At the …

Vue.js 官方團隊成員霍春陽新作,深入解析 Vue.js 設計細節【文末送書】

霍春陽&#xff08;Hcy&#xff09;&#xff0c;Vue.js 官方團隊成員。專注于 Web 研發領域&#xff0c;是 Vue.js 3 的核心貢獻者之一&#xff0c;Vue.js 文檔生成工具 Vuese 的作者&#xff0c;技術社區活躍者&#xff0c;曾撰寫大量頗受好評的技術博客。經過一年的準備&…

分享memcache和memcached安裝過程(轉)

Memcache是什么&#xff1f;源代碼地址&#xff1a;http://code.google.com/p/memcached/downloads/list Memcache是一個自由和開放源代碼、高性能、分配的內存對象緩存系統。用于加速動態web應用程序&#xff0c;減輕數據庫負載。 它可以應對任意多個連接&#xff0c;使用非阻…

LINQ之路 5:LINQ查詢表達式

書寫LINQ查詢時又兩種語法可供選擇&#xff1a;方法語法&#xff08;Fluent Syntax&#xff09;和查詢表達式&#xff08;Query Expression&#xff09;。 LINQ方法語法的本質是通過擴展方法和Lambda表達式來創建查詢。C# 3.0對于LINQ表達式還引入了聲明式的查詢表達式&#xf…

調查謀殺案以換取Obra Dinn

回顧性 (RETROSPECTIVE) I am not sure if this is intentional, but Lucas Pope has a knack for turning the mundane into something special. This was evident in his release of Papers Please. In that game, you’re a border patrolman trying to provide for your fa…

9年前的大一,我們這樣為女生過37女生節【祝節日快樂】

這是一篇水文~沒啥目的&#xff0c;若說要有&#xff0c;就是希望大家參加源碼共讀學起來。公眾號后臺顯示所有讀者朋友中大約有23%的女生。前端工程師中女生應該占比相對多些。祝關注我公眾號的女生3.7女生節快樂&#xff0c;大部分公司明天應該都有半天假期。可以留言大學時你…