volatile与内存屏障的关系与区别
C++中volatile关键字和内存屏障(Memory Barrier)的关系是什么?volatile是否能保证多线程内存可见性?为什么说volatile不适合线程间同步?volatile的正确使用场景是什么?
回答
编译有声
volatile的作用:
- 禁止编译器寄存器缓存(每次读取从内存重新加载)
- 禁止编译器对volatile操作重排序
- 不产生任何CPU指令级内存屏障
- 不保证原子性(多线程读写可能产生数据竞争)
volatile vs 内存屏障: | 特性 | volatile | 内存屏障 | |------|----------|---------| | 编译器重排 | 阻止 | 阻止 | | CPU重排 | 不阻止 | 阻止 | | 可见性保证 | 无 | 有(Acquire/Release) | | 原子性 | 无 | 需配合atomic |
为什么不能用于线程同步:
volatile bool ready = false;
// 线程1
ready = true; // 其他核心可能看不到此写入
// 线程2
if (ready) { } // 可能永远看不到ready=true
正确的做法是使用std::atomic<bool>或互斥锁。
volatile的正确使用场景:
- 硬件寄存器映射:
volatile uint32_t* reg = (uint32_t*)0x4000;——保证每次读写都访问设备 - 信号处理程序:C++11后
std::atomic_signal_fence更合适 - setjmp/longjmp场景:变量可能被longjmp修改
- 与多线程无关的特殊内存访问:如DMA缓冲区
C++标准说明[ISO C++ 7.1.6.1]:volatile是给编译器的提示——变量可能被程序外部修改。与线程无关。