一、 volatile
告诉编译器:这个变量的值随时可能被外部改变,禁止优化,每次读写必须直接访问内存,绝不使用寄存器缓存。
二、核心效果(C/C++)
- 禁止编译器优化:不把变量放进寄存器缓存,每次都从内存读/写
- 保证可见性:外部(硬件/中断/其他线程)修改后,主程序能立刻读到最新值
- 不保证原子性: volatile 不能替代互斥锁/原子操作
三、工控/嵌入式必用场景
- 硬件寄存器(GPIO/定时器/状态寄存器)
// 内存映射的硬件寄存器,必须 volatile
volatile uint32_t* GPIOA_ODR = (uint32_t*)0x40020014;
// 每次写都直接到硬件,不会被优化掉
*GPIOA_ODR |= (1 << 5);
硬件会自动改值,不加 volatile 编译器可能优化成"只写一次"。
- 中断与主循环共享变量
volatile bool g_flag = false;
// 中断里改
void TIM2_IRQHandler() {
g_flag = true;
}
// 主循环里读
while (1) {
if (g_flag) { // 每次都读内存,不会死循环
// 处理
g_flag = false;
}
}
不加 volatile ,编译器可能把 g_flag 读进寄存器,循环永远看不到变化。
- 多线程共享标志位
volatile bool run = true;
void thread_func() {
while (run) { ... }
}
// 主线程改 run,子线程能立刻看到
run = false;
仅用于简单标志;复杂同步必须用 mutex / atomic 。