色哟哟视频在线观看-色哟哟视频在线-色哟哟欧美15最新在线-色哟哟免费在线观看-国产l精品国产亚洲区在线观看-国产l精品国产亚洲区久久

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

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

3天內不再提示

C語言中的volatile是什么

jf_78858299 ? 來源:碼農的荒島求生 ? 作者:碼農的荒島求生 ? 2023-02-17 14:29 ? 次閱讀

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

volatile與編譯器

首先來看這樣一段代碼:

int busy = 1;
void wait() { while(busy) { ; }}

編譯一下,注意, 這里使用O2優化

圖片

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

wait:        mov     eax, DWORD PTR busy[rip].L2:        test    eax, eax        jne     .L2        retbusy:        .long   1

其中L2這一段即為while循環,這段指令是經過編譯器優化的,可以看到,決定能否跳出循環是通過檢查寄存器eax來完成的,而沒有檢查變量busy所在內存的真實內容。

注意,對于這段代碼來說這里的優化是正確的,但問題是如果還有其它代碼修改了變量busy,那么這里的優化會導致其它代碼對變量busy的修改根本就不能生效,就像這樣:

int busy = 1;
// 該函數在A線程中執行void wait() { while(busy) { ; }}
// 該函數在B線程中執行void signal() { busy = 0;}

如果wait函數中while循環對應的機器指令僅僅從寄存器中讀取數據那么即使B線程的signal函數修改了busy變量也不能讓wait函數從循環中跳出來。

如果你對busy變量使用volatile修飾,生成的指令就變成這樣了:

圖片

wait:.L2:        mov     eax, DWORD PTR busy[rip]        test    eax, eax        jne     .L2        retbusy:        .long   1

注意看此時L2這一段,每次都從busy變量所在的內存中讀取數據并存放在eax,然后再去判斷,這樣就能確保每次都能讀取到busy變量的最新值。

實際上你可以把寄存器eax當做busy所在內存的cache,當cache(寄存器)和內存中的數據一致時不會有任何問題,但當cache與內存中的數據不一致時(也就是內存已被更新但cache保存的還是舊數據),程序的運行往往出乎預料。

除了多線程的例子,還有一類就是signal handler以及硬件修改該變量(用C語言與硬件交互式時經常遇到),如果編譯器生成文章開頭那樣的指令那么等待線程將檢測不到signal handler或者硬件對變量的修改。

圖片

因此在這里我們需要告訴編譯器:“不要耍小聰明,不要只從寄存器中讀數據,這個變量可能在其它地方已經被修改了,使用時從內存中獲取最新數據”。

現在是時候簡單總結一下了, volatile僅僅阻止編譯器試圖去優化對變量的讀取操作

volatile與多線程

一定要注意volatile僅僅確保變量的可見性,但和變量的原子訪問沒有半毛錢關系,這是兩個完全不同的任務

假設有一個非常復雜的結構體struct foo:

struct data {  int a;  int b;  int c;  ...};
volatile struct data foo;
void thread1() { foo.a = 1; foo.b = 2; foo.c = 3; ...}
void thread2() { int a = foo.a; int b = foo.b; int c = foo.c; ...}

你僅僅用volatile去修飾變量foo只是確保了當該變量被thread1修改后我們能在thread2中讀取到最新值, 但是這解決不了多線程并發讀寫需要原子訪問foo的問題

確保變量原子性訪問一般都采用鎖,當使用鎖時,鎖本身就包含了volatile提供能力,即,確保變量的可見性,因此當使用鎖時沒有必要使用volatile。

volatile與memory order

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

volatile int busy = 0;

A線程讀取busy變量,B線程更新busy變量,當A檢測到busy變化后執行特定操作,這樣可行嗎?既然通過volatile修飾后可以確保每次都從內存中讀取busy,那么應該可以這樣使用吧。

然而,計算機在概念上可能相對簡單些,但在工程實踐中是復雜的。

我們知道由于CPU與內存之間的速度差異非常大,CPU與內存之間有一層cache,CPU其實并沒有直接讀取內存,cache的存在會讓問題復雜起來,限于篇幅與本文主題這里不再展開。

為優化內存讀寫,CPU可能會對內存讀寫操作進行指令重排,reordering,帶來的后果就是:假設在線程1中先后執行第N行代碼與第N+1行代碼,但在線程2看來卻是第N+1行代碼先生效,假設X的初始值為0,Y的初始值為1:

線程1           線程2
X = 10         if (!busy)
busy = 0;         Y = X;

當線程2檢測到busy為0后讀取X的值,此時讀取到的X值可能為0。

為解決這一問題,我們需要的不是volatile,volatile解決不了reordering問題,我們需要的是內存屏障,memory barrier。

內存屏障是一類機器指令,該指令對處理器在該屏障指令之前與之后的內存操作進行了限制,確保不會出現重排問題。

而內存屏障帶來的效果依然能夠涵蓋volatile提供的功能,因此也不需要volatile。

可以看到,在多線程環境下我們幾乎總是不會使用volatile關鍵字。

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

    關注

    180

    文章

    7614

    瀏覽量

    137431
  • 匯編
    +關注

    關注

    2

    文章

    214

    瀏覽量

    25972
  • volatile
    +關注

    關注

    0

    文章

    45

    瀏覽量

    13048
收藏 人收藏

    評論

    相關推薦

    c語言中 volatile _Bool 關鍵字說明

    這個帖子送給沒有太多實踐經驗的人,如果是大神,請跳過首先 _Bool 是C99新增的一個,用法和bool一樣, 如下圖: 雖然故意初始化為2,但是下邊變量顯示的值為1;然后為什么我要用
    發表于 01-06 10:46

    請問C語言中volatile有的作用是什么?

    C語言中volatile有什么用作用是什么?看到一個數組,別人這樣寫:volatile unsigned short adc_dma_buf[40];u32 ADCValue_ActC
    發表于 10-23 22:16

    STM32CubeMX的相關資料分享

    鏈接5中的代碼)1.C語言中volatile關鍵字的學習2.【STM32】HAL庫 STM32CubeMX教程十一—DMA (串口DMA發送接收)3.C
    發表于 01-14 07:10

    c語言中volatile關鍵字作用

    一個定義為volatile 的變量是說這變量可能會被意想不到地改變,這樣,編譯器就不會去假設這個變量的值了。精確地說就是,優化器在用到這個變量時必須每次都小心地重新讀
    發表于 06-22 17:04 ?46次下載

    C語言中volatile關鍵字

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

    C語言中指針的介紹非常詳細

    C語言中指針的介紹非常詳細 C語言中指針的介紹非常詳細
    發表于 12-25 10:39 ?57次下載

    C語言和匯編語言混合編程方法和C語言中斷處理方法

    C語言和匯編語言混合編程方法和C語言中斷處理方法,new
    發表于 01-06 14:36 ?36次下載

    C語言中的關鍵字

    C語言中的入門教程
    發表于 10-14 16:24 ?3次下載

    C語言中volatile關鍵字的使用

    volatile 的意思是易變的、可變的,作用是限制編譯器優化某些變量。首先看一段C51程序: Keil在優化級別是為8時得到如下匯編代碼(部分未列出):可以看到,變量d的值賦給x,y,z時,只有x
    的頭像 發表于 03-17 11:55 ?1.3w次閱讀
    <b class='flag-5'>C</b><b class='flag-5'>語言中</b><b class='flag-5'>volatile</b>關鍵字的使用

    C語言類型修飾符Volatile的使用說明

    C語言是我們經常需要用到的語言C語言中的類型修飾符Volatile大家知道怎么使用嗎?
    的頭像 發表于 09-19 10:54 ?3574次閱讀

    總結那么幾個C語言中的“坑”

    總結幾個C語言中的“坑”
    的頭像 發表于 01-16 10:52 ?2620次閱讀

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

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

    HAL庫STM32串口DMA不定長收發,空閑中斷

    參考了鏈接5中的代碼)1.C語言中volatile關鍵字的學習2.【STM32】HAL庫 STM32CubeMX教程十一—DMA (串口DMA發送接收)3.C
    發表于 01-14 10:40 ?19次下載
    HAL庫STM32串口DMA不定長收發,空閑中斷

    c#語言中怎么使用HTTP代理

    c#語言中怎么使用HTTP代理。
    的頭像 發表于 09-01 14:46 ?2180次閱讀

    C語言中的socket編程基礎

    Socket編程簡介 Socket是一種通信機制,允許程序之間進行通信。在C語言中,socket編程是網絡編程的基礎。通過使用socket,程序可以發送和接收數據,實現不同計算機之間的通信
    的頭像 發表于 11-01 16:51 ?425次閱讀
    主站蜘蛛池模板: 国产盗摄一区二区 | 色戒床震视频片段 | 亚洲国产精品热久久 | 一线高清视频在线播放 | 最近的2019中文字幕HD | 影音先锋av男人资源 | 97在线播放视频 | 99热在线精品免费全部my | 中文字幕 日韩 无码 在线 | 亚洲人成在线观看一区二区 | 99久久免热在线观看6 | 国产大片51精品免费观看 | 神马电影我不卡4k手机在线观看 | 欧美最猛黑人XXXXWWW | 精品一区二区免费视频蜜桃网 | 青娱国产区在线 | 97色伦亚洲自偷 | jyzzjyzzz视频国产在线观看 | 人人干人人插 | 一品道门在线视频 | 空姐内射出白浆10p 空姐厕所啪啪啪 | 亚洲一区二区影院 | 国产精品久久久久影院免费 | 久久偷拍国2017 | 伊人久久一本 | 阴茎插入阴道 | 丝瓜视频樱桃视频在线观看免费 | YELLOW视频直播在线观看高清 | 色狠狠一区二区 | 综合色就爱涩涩涩综合婷婷 | 日本调教网站 | 一一本之道高清视频在线观看中文字幕 | 精子网久久国产精品 | 狠狠色狠狠色狠狠五月ady | 亚洲国产成人精品青青草原100 | 亚洲三级在线视频 | 9久久免费国产精品特黄 | 羞羞在线观看 | 中文字幕免费视频精品一 | 国产又湿又黄又硬又刺激视频 | 国产99小视频 |