volatile是什么

一、背景和問題描述

假設你寫的這個多線程程序中,有兩個線程:

  • 子線程(thr:把flag變量設為1,并輸出“modify flag to 1”;
  • 主線程:一直在循環等待,直到flag變成1,然后退出。

代碼示范:

#include <thread>
#include <iostream>int flag = 0;int main() {std::thread thr([]() {flag = 1;std::cout << "modify flag to 1" << std::endl;});while (flag == 0) {// 等待}thr.join();return 0;
}

你可能期待:

  • 子線程修改flag后,主線程馬上檢測到flag已變為1,然后退出。
  • 這實際上理論上沒問題,但在某些環境(比如用gcc 4.8.5編譯)下,結果會“卡死”,一直卡在while循環里,沒人退出。

二、為什么會卡住?關鍵原因:編譯器優化和緩存機制

這其實是一個“多線程可見性”的問題。

為什么?

  • 現代的編譯器和處理器有“優化”機制:它們會試圖加快程序運行速度。
  • 在沒有特殊指示的情況下,編譯器可能會“假定”flag在主線程中沒有被別的線程改變,尤其是在沒有使用同步原語的情況下。
  • 結果
    • 編譯器會把flag的值“緩存”到寄存器里,讀操作只在內存之前的值;
    • 導致每次循環都用“舊”的值判斷(比如一直是0),不會到主存去讀取最新的flag的值。

總結

  • **沒有volatile時,**編譯器可能會“優化”掉每次都去內存重新讀取flag的操作,而只用緩存的值來判斷,從而導致死循環。

三、volatile的作用

在C++中,volatile告訴編譯器:“請不要對這個變量做優化,不要緩存,必須每次都從內存讀取”。

改寫代碼:

#include <thread>
#include <iostream>volatile int flag = 0;int main() {std::thread thr([]() {flag = 1;std::cout << "modify flag to 1" << std::endl;});while (flag == 0) {// 等待}thr.join();return 0;
}

效果:

  • 通過volatile,每次while循環檢測flag的值時,都會從內存中重新加載,而不是用寄存器里的“緩存值”。
  • 這樣,在子線程修改了flag,主線程就能及時看到到flag==1,退出循環。

四、底層匯編分析:為什么volatile有效

這部分內容很核心,理解它可以幫你明白volatile的作用。

沒有volatile時:

  • 編譯器會“優化”代碼,比如:
    • 只在循環開始時讀取flag一次;
    • 在循環中,只用寄存器里的緩存值判斷,完全避免每次都去內存讀取。

用匯編表示:

  • 這樣,主線程每次判斷flag時,都是用一開始的值(例如0),即使子線程后來改了flag,主線程的flag值“沒有變化”。

volatile時:

  • 編譯器會插入“指令”,確保每次判斷前,都會從內存重新讀取flag的值。
  • 在匯編里表現為:每次碰到flag,都用movl(加載指令)重新加載變量的最新內容。

這樣,子線程一修改flag,主線程就能立刻看到變化。


五、額外提醒:volatile的局限性

💡?volatile不是多線程同步的“護身符”

  • 它只保證“每次讀寫都從內存加載/存儲”,但不能保證“多線程之間的同步”,或“操作的原子性”。
  • 現代多線程編程建議用**std::atomic**,它能保證:
    • 原子操作(操作步驟不可被打斷);
    • 可見性(一線程修改,另一線程馬上看到);
    • 內存序列一致性

總結:

  • volatile在多線程中的作用主要是阻止編譯器優化變量,讓變量每次都從內存重新讀取。
  • 在實際多線程開發中,volatile不足以保證同步,應優先考慮std::atomic或其他同步機制。

六、總結一覽

主題內容描述
volatile作用告訴編譯器不要優化變量,強制每次操作都從內存中讀寫。
遇到的問題編譯器會“緩存”讀操作,導致多線程中一個線程修改的值,另一個線程看不到(死循環、程序卡死等)。
使用場景主要用于硬件狀態寄存器、特殊情況的標志變量,但不替代同步工具。
更好的方案使用std::atomic保證線程安全和易維護。

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

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

相關文章

MySQL的Docker版本,部署在ubantu系統

前言 MySQL的Docker版本&#xff0c;部署在ubantu系統&#xff0c;出現問題&#xff1a; 1.執行一個SQL&#xff0c;只有錯誤編碼&#xff0c;沒有錯誤提示信息&#xff0c;主要影響排查SQL運行問題&#xff1b; 2.這個問題&#xff0c;并不影響實際的MySQL運行&#xff0c;如…

專欄特輯丨懸鏡淺談開源風險治理之SBOM與SCA

隨著容器、微服務等新技術日新月異&#xff0c;開源軟件成為業界主流形態&#xff0c;軟件行業快速發展。但同時&#xff0c;軟件供應鏈也越來越趨于復雜化和多樣化&#xff0c;軟件供應鏈安全風險不斷加劇。 軟件供應鏈安全主要包括軟件開發生命周期和軟件生存運營周期&#x…

18.Excel數據透視表:第1部分創建數據透視表

一 什么是數據透視表 通過萬花筒可以用不同的方式査看里面畫面圖像&#xff0c;在excel中可以將數據透視表看作是對準數據的萬花筒&#xff0c;用不同角度去觀察數據&#xff0c;也可以旋轉數據&#xff0c;對數據進行重新排列&#xff0c;對大量的數據可以快速的匯總和建立交叉…

商業航天運動控制系統中的高可靠性芯片解決方案:挑戰、策略與應用研究

摘要&#xff1a;隨著商業航天領域的迅速發展&#xff0c;運動控制系統對芯片的可靠性提出了前所未有的挑戰。本文深入探討了商業航天運動控制系統中芯片可靠性面臨的挑戰&#xff0c;包括宇宙輻射效應、極端環境適應性及系統級可靠性保障等。同時&#xff0c;通過案例研究展示…

音視頻學習:使用NDK編譯FFmpeg動態庫

1. 環境 1.1 基礎配置 NDK 22b (r22b)FFmpeg 4.4Ubuntu 22.04 1.2 下載ffmpeg 官網提供了 .tar.xz 包&#xff0c;可以直接下載解壓&#xff1a; wget https://ffmpeg.org/releases/ffmpeg-4.4.tar.xz tar -xvf ffmpeg-4.4.tar.xz cd ffmpeg-4.41.3 安裝基礎工具鏈 sudo …

前端開發避坑指南:React 代理配置常見問題與解決方案

前端開發避坑指南:React 代理配置常見問題與解決方案 一、為什么需要配置代理?二、使用 create-react-app 默認配置代理三、使用 http-proxy-middleware 配置復雜代理四、高級代理配置五、生產環境中的代理配置一、為什么需要配置代理? React 應用在開發過程中經常需要與后端…

用影刀RPA打通內容創作“最后一公里”:CSDN草稿一鍵同步多平臺發布

文章目錄 引言 一、需求場景&#xff1a;多平臺分發的效率困境1. 痛點分析2. 影刀RPA的破局價值 二、影刀RPA是啥&#xff1f;打工人逆襲神器&#xff01;三、手把手教你造"搬運工"——技術宅的土味開發日記第一步&#xff1a;當個"偷窺狂"——觀察手動操作…

進程與線程:09 進程同步與信號量

課程引入&#xff1a;進程同步與信號量 接下來這節課開始&#xff0c;我們再開始講多進程圖像。講多進程圖像的下一個點&#xff0c;前面我們講清楚了多進程圖像要想實現切換&#xff0c;調度是如何做的。同時&#xff0c;多個進程放在內存中&#xff0c;就會存在多進程合作的…

【愚公系列】《Manus極簡入門》036-物聯網系統架構師:“萬物互聯師”

&#x1f31f;【技術大咖愚公搬代碼&#xff1a;全棧專家的成長之路&#xff0c;你關注的寶藏博主在這里&#xff01;】&#x1f31f; &#x1f4e3;開發者圈持續輸出高質量干貨的"愚公精神"踐行者——全網百萬開發者都在追更的頂級技術博主&#xff01; &#x1f…

MySQL 8.0 OCP 英文題庫解析(四)

Oracle 為慶祝 MySQL 30 周年&#xff0c;截止到 2025.07.31 之前。所有人均可以免費考取原價245美元的MySQL OCP 認證。 從今天開始&#xff0c;將英文題庫免費公布出來&#xff0c;并進行解析&#xff0c;幫助大家在一個月之內輕松通過OCP認證。 本期公布試題26~30 試題26:…

什么是原碼和補碼

補碼的本質確實是模運算&#xff08;Modular Arithmetic&#xff09;&#xff0c;這是理解補碼為何能統一加減法的核心數學原理。下面用最通俗的語言和例子解釋清楚&#xff1a; —### 1. 先理解什么是“模運算”- 模運算就是“周期性計數”&#xff0c;比如鐘表&#xff1a; -…

筆記項目 day02

一、用戶登錄接口 請求參數&#xff1a; 用loginDTO來封裝請求參數&#xff0c;要加上RequestBody注解 響應參數&#xff1a; 由于data里內容較多&#xff0c;考慮將其封裝到一個LoginUser的實體中&#xff0c;用戶登陸后&#xff0c;需要生成jwtToken并返回給前端。 登錄功…

2025年土木建筑與水利工程國際會議(ICCHE 2025)

2025 International Conference on Civil and Hydraulic Engineering (ICCHE 2025) &#xff08;一&#xff09;會議信息 會議簡稱&#xff1a;ICCHE 2025 大會地點&#xff1a;中國銀川 投稿郵箱&#xff1a;icchesub-paper.com 收錄檢索&#xff1a;提交Ei Compendex,CPCI,C…

運行Spark程序-在shell中運行1

&#xff08;一&#xff09;分布式計算要處理的問題 【老師提問&#xff1a;分布式計算要面臨什么問題&#xff1f;】 【老師總結】 分布式計算需要做到&#xff1a; 1.分區控制。把大的數據拆成一小份一小份的&#xff08;分區&#xff0c;分片&#xff09;讓多臺設備同時計算…

一文理清人工智能,機器學習,深度學習的概念

目錄 一、人工智能的起源與核心范疇&#xff08;1950-1980&#xff09; 1.1 智能機器的最初構想 1.2 核心范疇的初步分化 二、機器學習的興起與技術分化&#xff08;1980-2010&#xff09; 2.1 統計學習的黃金時代 2.2 神經網絡的復興與子集定位 2.3 技術生態的形成與AI…

《Effective Python》第1章 Pythonic 思維總結——編寫優雅、高效的 Python 代碼

《Effective Python》第1章 Pythonic 思維總結——編寫優雅、高效的 Python 代碼 在編程的世界里&#xff0c;每個語言都有其獨特的風格和最佳實踐。對于 Python 而言&#xff0c;“Pythonic”已經成為描述遵循 Python 特定風格的代碼的代名詞。這種風格不僅讓代碼更易讀、更簡…

MySQL 事務(二)

文章目錄 事務隔離性理論理解隔離性隔離級別 事務隔離級別的設置和查看事務隔離級別讀未提交讀提交&#xff08;不可重復讀&#xff09; 事務隔離性理論 理解隔離性 MySQL服務可能會同時被多個客戶端進程(線程)訪問&#xff0c;訪問的方式以事務方式進行一個事務可能由多條SQL…

代碼倉提交分支規范

以下是我部門開發時用的分支規范&#xff0c;參考于Linux社區 Tips 分支命名通常遵循一些最佳實踐和規則&#xff0c;以便使分支的用途和內容清晰易懂&#xff0c;就在寫一個文檔的主題一樣。 功能分支 (Feature Branches) 用于開發新功能。 命名格式&#xff1a;feature/功能名…

Google Earth Engine(GEE) 代碼詳解:批量計算_年 NDVI 并導出(附 Landsat 8 數據處理全流程)

一、代碼整體目標 基于 Landsat 8 衛星數據,批量計算 2013-2020 年研究區的 NDVI(歸一化植被指數),實現去云處理、數據合成、可視化及批量導出為 GeoTIFF 格式,適用于植被動態監測、生態環境評估等場景。 二、代碼分步解析(含核心原理與易錯點) 1. 加載并顯示研究區邊…

Maven 處理依賴沖突

Maven處理依賴沖突 什么是依賴沖突&#xff1f;如何解決&#xff1f;Maven自動處理依賴沖突的規則路徑優先原則第一聲明優先原則注意 子模塊覆蓋父模塊父模塊聲明dependency子模塊覆蓋dependency父模塊聲明dependencyManagement 子模塊覆蓋dependency父模塊聲明dependencyManag…