0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

C語言中的關鍵字volatile到底有什么用呢

冬至配餃子 ? 來源:碼農(nóng)的荒島求生 ? 作者:陸小風 ? 2022-08-19 15:20 ? 次閱讀

C語言時有一個奇怪的關鍵字volatile,這到底有什么用呢?

volatile與編譯器

首先來看這樣一段代碼:

poYBAGL_OPqAJcX1AAAmuspJiPM513.png

編譯一下,注意,這里使用O2優(yōu)化

poYBAGL_OQuAUL6RAABH_m-ekkU022.png

讓我們仔細看看生成的這段匯編

poYBAGL_ORuAbQaYAAAx5NlEoUA148.png

其中L2這一段即為while循環(huán),這段指令是經(jīng)過編譯器優(yōu)化的,可以看到,決定能否跳出循環(huán)是通過檢查寄存器eax來完成的,而沒有檢查變量busy所在內存的真實內容。注意,對于這段代碼來說這里的優(yōu)化是正確的,但問題是如果還有其它代碼修改了變量busy,那么這里的優(yōu)化會導致其它代碼對變量busy的修改根本就不能生效,就像這樣:

poYBAGL_OS2AX76OAABCqHuCaHk299.png

如果wait函數(shù)中while循環(huán)對應的機器指令僅僅從寄存器中讀取數(shù)據(jù)那么即使B線程的signal函數(shù)修改了busy變量也不能讓wait函數(shù)從循環(huán)中跳出來。如果你對busy變量使用volatile修飾,生成的指令就變成這樣了:

poYBAGL_OUGAJgWUAAB5XeDiP-A019.png

注意看此時L2這一段,每次都從busy變量所在的內存中讀取數(shù)據(jù)并存放在eax,然后再去判斷,這樣就能確保每次都能讀取到busy變量的最新值。實際上你可以把寄存器eax當做busy所在內存的cache,當cache(寄存器)和內存中的數(shù)據(jù)一致時不會有任何問題,但當cache與內存中的數(shù)據(jù)不一致時(也就是內存已被更新但cache保存的還是舊數(shù)據(jù)),程序的運行往往出乎預料。除了多線程的例子,還有一類就是signal handler以及硬件修改該變量(用C語言與硬件交互式時經(jīng)常遇到),如果編譯器生成文章開頭那樣的指令那么等待線程將檢測不到signal handler或者硬件對變量的修改。

pYYBAGL_OVOADcaxAABWCJPCGqM654.png

因此在這里我們需要告訴編譯器:“不要耍小聰明,不要只從寄存器中讀數(shù)據(jù),這個變量可能在其它地方已經(jīng)被修改了,使用時從內存中獲取最新數(shù)據(jù)”?,F(xiàn)在是時候簡單總結一下了,volatile僅僅阻止編譯器試圖去優(yōu)化
對變量的讀取操作
。

volatile與多線程一定要注意volatile僅僅確保變量的可見性,但和變量的原子訪問沒有半毛錢關系,這是兩個完全不同的任務。假設有一個非常復雜的結構體struct foo:

poYBAGL_OWaACKRUAABuHEE_1Qk178.png

你僅僅用volatile去修飾變量foo只是確保了當該變量被thread1修改后我們能在thread2中讀取到最新值,但是這解決不了多線程并發(fā)讀寫需要原子訪問foo的問題。確保變量原子性訪問一般都采用鎖,當使用鎖時,鎖本身就包含了volatile提供能力,即,確保變量的可見性,因此當使用鎖時沒有必要使用volatile。

volatile與memory order有的同學可能會想如果我想用volatile修飾的變量沒有那么復雜,僅僅是一個int,就像這樣:

pYYBAGL_OXeAIeSZAAAVhwVO_pw844.png

A線程讀取busy變量,B線程更新busy變量,當A檢測到busy變化后執(zhí)行特定操作,這樣可行嗎?既然通過volatile修飾后可以確保每次都從內存中讀取busy,那么應該可以這樣使用吧。然而,計算機在概念上可能相對簡單些,但在工程實踐中是復雜的。我們知道由于CPU與內存之間的速度差異非常大,CPU與內存之間有一層cache,CPU其實并沒有直接讀取內存,cache的存在會讓問題復雜起來,限于篇幅與本文主題這里不再展開。為優(yōu)化內存讀寫,CPU可能會對內存讀寫操作進行指令重排,reordering,帶來的后果就是:假設在線程1中先后執(zhí)行第N行代碼與第N+1行代碼,但在線程2看來卻是第N+1行代碼先生效,假設X的初始值為0,Y的初始值為1:

poYBAGL_OYmASB2jAAAdTvpeW0g039.png

當線程2檢測到busy為0后讀取X的值,此時讀取到的X值可能為0。為解決這一問題,我們需要的不是volatile,volatile解決不了reordering問題,我們需要的是內存屏障,memory barrier。內存屏障是一類機器指令,該指令對處理器在該屏障指令之前與之后的內存操作進行了限制,確保不會出現(xiàn)重排問題。而內存屏障帶來的效果依然能夠涵蓋volatile提供的功能,因此也不需要volatile??梢钥吹剑诙嗑€程環(huán)境下我們幾乎總是不會使用volatile關鍵字。



審核編輯:劉清

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權轉載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • 處理器
    +關注

    關注

    68

    文章

    19038

    瀏覽量

    228459
  • 寄存器
    +關注

    關注

    31

    文章

    5271

    瀏覽量

    119648
  • C語言
    +關注

    關注

    180

    文章

    7581

    瀏覽量

    135579
收藏 人收藏

    評論

    相關推薦

    教科書不會講的C語言關鍵字volatile用法

    許多程序員都無法正確理解C語言關鍵字 volatile,這并不奇怪。因為大多數(shù)C語言書籍通常都是
    發(fā)表于 02-02 10:14 ?461次閱讀

    C語言關鍵字volatile的用法

    許多程序員都無法正確理解C語言關鍵字volatile,這并不奇怪。因為大多數(shù)C語言書籍通常都是一
    發(fā)表于 04-11 09:35 ?2503次閱讀

    c語言中 volatile _Bool 關鍵字說明

    volatile 關鍵字?volatile總是與優(yōu)化有關,編譯器一種技術叫做數(shù)據(jù)流分析,分析程序中的變量在哪里賦值、在哪里使用、在哪里
    發(fā)表于 01-06 10:46

    編譯器的“關鍵字到底有關鍵?

    DSP編程什么技巧?使用代碼優(yōu)化時必須考慮哪些問題?C28x的編譯器支持哪些“關鍵字”?編譯器的“關鍵字到底有
    發(fā)表于 04-19 06:32

    【原創(chuàng)分享】單片機編程關鍵字volatile

    很多人來說,根本沒見過這個關鍵字,不知道它的存在。也有很多人知道它的存在,根本沒用過,我對它有種“楊家有女初長成,養(yǎng)在深閨無人識”的感覺。那么volatile關鍵字到底是什么意思
    發(fā)表于 06-29 11:17

    C語言volatile關鍵字詳解 精選資料分享

    1.volatile和什么有關百度翻譯是這樣子翻譯volatile的:圖1-1 百度翻譯volatile截圖volatile屬于C
    發(fā)表于 07-22 07:20

    Volatile關鍵字對于嵌入式開發(fā)有什么作用

    前言在進行嵌入式開發(fā)中,我們往往會看到一個名為volatile或者__IO的關鍵字,那么,它們對于嵌入式開發(fā)有什么作用?淺析volatile數(shù)據(jù)類型實際上,__IO和
    發(fā)表于 11-05 09:20

    C語言volatile關鍵字之間什么關系?

    C語言volatile關鍵字之間什么關系?
    發(fā)表于 11-11 07:01

    C語言中關鍵字static的作用是什么

    C語言中關鍵字static的作用是什么?預處理指令#define 聲明一個函數(shù),輸入天數(shù)得到多少秒?
    發(fā)表于 12-24 06:53

    C語言中volatile關鍵字

    volatile關鍵字是一種類型修飾符,用它聲明的類型變量表示可以被某些編譯器未知的因素更改。
    發(fā)表于 05-27 09:32 ?3256次閱讀

    單片機C語言中常用到的關鍵字及數(shù)據(jù)類型

    單片機C語言中常用到的關鍵字及數(shù)據(jù)類型。
    發(fā)表于 11-03 10:57 ?13次下載

    【嵌入式】C語言中volatile關鍵字

    volatile06. 附錄01. volatile概述volatileC語言中的一個關鍵字
    發(fā)表于 10-21 10:21 ?6次下載
    【嵌入式】<b class='flag-5'>C</b><b class='flag-5'>語言中</b><b class='flag-5'>volatile</b><b class='flag-5'>關鍵字</b>

    C語言中volatile是什么

    C語言時有一個奇怪的關鍵字volatile,這到底有什么用
    的頭像 發(fā)表于 02-17 14:29 ?1171次閱讀
    <b class='flag-5'>C</b><b class='flag-5'>語言中</b>的<b class='flag-5'>volatile</b>是什么

    淺析C語言中的regiseter關鍵字

    C語言中重要的關鍵字很多,static const extern我們之前都講過,還有一個在面試中出現(xiàn)的頻率也比較高:register。
    的頭像 發(fā)表于 08-25 17:10 ?1049次閱讀
    淺析<b class='flag-5'>C</b><b class='flag-5'>語言中</b>的regiseter<b class='flag-5'>關鍵字</b>

    快速掌握C語言關鍵字

    C語言中的32個關鍵字你知道多少個?根據(jù)關鍵字的作用分為四類:數(shù)據(jù)類型關鍵字、控制語句
    的頭像 發(fā)表于 07-06 08:04 ?249次閱讀
    快速掌握<b class='flag-5'>C</b><b class='flag-5'>語言</b><b class='flag-5'>關鍵字</b>