volatile用于防止编译器对可能被程序外修改的变量进行优化,适用于硬件寄存器、信号处理、内存映射I/O和ISR共享变量;但它不保证线程安全、原子性或CPU指令有序性,多线程中应使用std::atomic。

volatile 告诉编译器:这个变量的值可能在程序控制之外被改变,禁止对它做某些优化。
嵌入式场景中防止寄存器读写被优化
在驱动或裸机编程中,硬件寄存器地址常映射为指针变量。若不加 volatile,编译器可能把多次读取优化成一次,或把看似“无用”的写操作直接删掉——这会导致外设无法响应。
- 比如轮询某个状态寄存器:while (*(volatile uint32_t*)0x40020000 == 0); —— 每次都必须真实读内存,不能缓存或省略
- 向控制寄存器连续写两个值:REG->CR = 1; REG->CR = 2; —— 编译器不能合并或重排,否则硬件行为异常
多线程中不能替代同步机制
很多人误以为 volatile 能保证线程间可见性或原子性,其实它只解决编译器层面的重排序和缓存问题,不涉及 CPU 指令重排、缓存一致性协议(如 MESI)或原子操作。
- 它不会插入内存屏障(memory barrier),CPU 仍可能乱序执行
- ++ 操作本身不是原子的(读-改-写三步),volatile 无法阻止其他线程在中间插手
- C++11 后应优先使用 std::atomic
,它既保证可见性、有序性,又提供原子操作语义
什么时候该用 volatile
仅当变量可能被以下方式意外修改时才需 volatile:
立即学习“C++免费学习笔记(深入)”;
- 硬件寄存器(如定时器计数器、GPIO 状态位)
- 信号处理函数中修改的全局变量(且未用 sig_atomic_t)
- 内存映射 I/O 区域中的变量
- 与中断服务程序(ISR)共享的标志位(注意:仍需合理同步,避免竞态)
常见误区提醒
volatile 不等于线程安全,也不等于原子性:
- volatile bool flag = false; —— 多线程中 flag 被一个线程置 true,另一个线程可能因 CPU 缓存延迟很久才看到,volatile 无法强制刷新缓存行
- volatile int counter = 0; —— counter++ 在多线程下仍是数据竞争,结果不可预测
- 它不阻止编译器将 volatile 变量放入寄存器(某些平台/优化级别下仍可能临时缓存),只是禁止跨语句的冗余读写消除








