【C++11】volatile 关键字

文章目录

  • 一、基本作用

  • 二、应用场景

    • [2.1 硬件寄存器访问](#2.1 硬件寄存器访问)
    • [2.2 多线程环境中的信号处理](#2.2 多线程环境中的信号处理)
    • [2.3 内存映射 I/O](#2.3 内存映射 I/O)
  • [三、不用 volatile 导致的问题](#三、不用 volatile 导致的问题)

    • [3.1 死循环问题](#3.1 死循环问题)
    • [3.2 编译器优化导致的逻辑错误](#3.2 编译器优化导致的逻辑错误)
  • 四、小结

  • C++11 之前,volatile 常被误用于多线程同步;C++11 引入标准内存模型和 std::atomic 后,volatile 被明确限定仅用于硬件寄存器、信号处理等非并发场景,不再适用于多线程同步。

一、基本作用

  • volatile 是 C++ 中的一个类型限定符(type qualifier),用于告诉编译器: 该变量的值可能会在程序的控制之外被改变 ,因此 编译器不能对该变量进行某些优化(防止编译器将变量缓存在寄存器中),每次使用变量时都必须从内存中重新读取。 确保对变量的修改对其他可能修改它的实体可见。

二、应用场景

2.1 硬件寄存器访问

cpp 复制代码
// 访问硬件状态寄存器
volatile uint32_t* status_register = reinterpret_cast<volatile uint32_t*>(0x40000000);

while ((*status_register & 0x1) == 0) {
    // 等待硬件就绪标志位被置位
    // ⚠️如果没有 volatile,编译器可能只读取一次并缓存结果
}

2.2 多线程环境中的信号处理

cpp 复制代码
volatile bool signal_received = false;

void signal_handler(int sig) {
    signal_received = true;  // 信号处理器修改变量
}

int main() {
    signal(SIGINT, signal_handler);
    while (!signal_received) {
        // 执行工作
        // ⚠️必须使用 volatile,否则编译器可能优化掉重复检查
    }
    return 0;
}

2.3 内存映射 I/O

cpp 复制代码
// 内存映射的显示缓冲区
volatile char* display_buffer = reinterpret_cast<volatile char*>(0xA0000000);
for (int i = 0; i < 100; ++i) {
    display_buffer[i] = 'A' + i;  // 每次写入都必须实际执行
}

三、不用 volatile 导致的问题

3.1 死循环问题

cpp 复制代码
// ❌️错误示例:没有使用 volatile
bool flag = false;

void interrupt_handler() {
    flag = true;  // 在中断或信号处理器中设置
}

void wait_for_flag() {
    while (!flag) {
        // ⚠️ 编译器可能优化为:只读取一次 flag 的值
        // 如果初始值为 false,就会陷入死循环!
    }
}

// ✅️正确做法:
volatile bool flag = false;  // ✅️ 添加 volatile

3.2 编译器优化导致的逻辑错误

cpp 复制代码
// 模拟硬件寄存器

// ❌️错误:没有 volatile
uint32_t hardware_status = 0;
void wait_for_hardware() {
    while (hardware_status == 0) {
        // ⚠️编译器可能将 hardware_status 缓存在寄存器中
        // 即使硬件改变了内存中的值,循环也不会退出
    }
}

// ✅️正确:使用 volatile
volatile uint32_t hardware_status = 0;
void wait_for_hardware_correct() {
    while (hardware_status == 0) {
        // 每次都会从内存重新读取 hardware_status
    }
}

四、小结

  • volatile ≠ 线程安全,volatile 不能保证原子性。
cpp 复制代码
// volatile 不能保证原子性!
volatile int shared_var = 0;

// 在多线程中,shared_var++ 仍然不是原子操作
// 需要使用 std::atomic 或互斥锁
  • 性能影响
    • 每次访问都必须访问内存,无法使用寄存器缓存
    • 可能影响性能,只在必要时使用
相关推荐
老歌老听老掉牙30 分钟前
圆柱端面四平面交线及其在yoz面投影的几何解析与 Python 实现
开发语言·python·平面
繁星蓝雨36 分钟前
C++设计原理———多重继承(虚基类、菱形继承、委托、重命名、基类和成员初始化)
c++·委托·多重继承·mi·显式初始化列·虚基类·对象布局
旖旎夜光1 小时前
【C++ 基础入门】命名空间、输入输出、缺省参数与函数重载
开发语言·c++·笔记·学习
俩个逗号。。1 小时前
Kotlin flow 详解
android·开发语言·kotlin
程序猿乐锅2 小时前
万字详解Single-flight(单飞模式)
java·开发语言·分布式·后端·学习·single-flight
扶尔魔ocy2 小时前
【QT入门到晋级】用开源的自定义控件开发
c++·qt·自定义控件
akinggw3 小时前
libsherpacore - 基于 sherpa-onnx 的 C++ 语音交互静态库
c++·交互·语音识别
xiaoye-duck4 小时前
《C++ 项目:手写大模型接入 SDK》ChatGPT接口设计(中):全量响应实现和测试
网络·c++·语言模型·chatgpt
揽星河..4 小时前
【C语言】指针
c语言·开发语言
小小数媒成员4 小时前
UGUI原理(一)
开发语言·游戏·unity·游戏引擎