C++ - volatile、std::atomic、std::mutex 区别与联系
简介
1、一般 volatile 和 std::atomic 容易产生误用
2、一般 std::atomic 和 std::mutex 容易产生误用
对第1点
| 特性 | volatile | std::atomic |
|---------------|------------------------------------|-----------------------|
| 核心作用 | 禁止编译器优化,保证内存可见性 | 保证原子性+内存可见性 |
| 适用操作 | 简单读写(赋值/读取) | 读-改-写(++/--/+=)|注:++是读-改-写三步
| 多线程安全 | 不安全(无原子性) | 安全(原子操作) |
| 典型场景 | 硬件寄存器、信号处理函数 | 多线程计数器、标志位 |
误区:
很多人加volatile是误以为 “能增强std::atomic的安全性”,但实际:
❌ 误区 1:volatile能让std::atomic更 “安全”—— 不存在,std::atomic的原子性和可见性已经是最高级别的保证;
❌ 误区 2:volatile能提升std::atomic的性能 —— 反而可能轻微降低性能(编译器优化被进一步限制);
✅ 事实:只有变量关联硬件时,volatile才有实际意义,纯软件场景完全多余。
总结
1. volatile 的核心:禁止编译器优化变量的读写,保证每次操作都直接访问内存;
2. 唯一适用场景:硬件寄存器操作、信号处理函数的全局变量、多线程简单标志位(仅保证可见性);
3. 关键避坑:`volatile`≠原子性,多线程原子操作必须用`std::atomic`;
4. 原则:不滥用,仅在编译器可能优化掉变量读写时使用,否则会降低程序效率。
5. 日常开发(纯软件多线程):std::atomic<int>无需加volatile,加了也无收益;
6. 嵌入式 / 硬件交互:仅当std::atomic变量映射到硬件寄存器时,才需要叠加volatile;
7. volatile 和 const 可共存,一般写法 const volatile int a,因为值可被外部修改(如硬件只读寄存器)
对第2点
std::atomic:针对单个变量;快/纳秒/没有内核到用户态切换开销;只支持基础类型/struct;只支持++/--/+=/=右值/左值=
std::mutex:针对代码块;相对慢/微秒/有内核到用户态切换开销;不受类型约束;支持复杂操作
注:
1. 两者使用效率只有在合适地方才能最高,如果应该在使用std::mutex场景使用std::atomic反而整体效率变低
2. std::mutex需要配合管理锁std::lock_guard这类使用,保证离开生命周期就解锁
3. 两者使用时对应线程操作变量都是无序的,且1线程获得锁时2线程会阻塞等待(但不消耗CPU,非自旋锁)
END
浙公网安备 33010602011771号