编译器是否允许合并relaxed内存序的重复原子存储?为何未做该优化?
问题
以下代码:
#include <atomic> std::atomic_bool b; void store2() { b.store(true, std::memory_order::relaxed); b.store(true, std::memory_order::relaxed); }
GCC、MSVC和Clang均生成如下两条mov指令:
store2(): mov BYTE PTR b[rip], 1 mov BYTE PTR b[rip], 1 ret b: .zero 1
是否允许将这两次原子存储合并为一条mov指令?我认为这不会违反std::memory_order::relaxed的限制,因为其他线程观察到的效果与单次存储一致。
若该操作是允许的,为何主流编译器不执行这一简单优化?
是否允许合并?
是,这种合并完全符合C++标准。对于std::memory_order::relaxed的原子操作,标准仅要求两点:
- 同一线程内的操作遵循程序顺序(线程自身能感知代码的执行顺序)
- 对同一原子对象的所有操作,存在全局一致的修改顺序(所有线程看到的对象修改序列统一)
两次存储相同值的relaxed原子操作合并后,完全满足上述约束:其他线程观察到的对象状态变化和原代码完全一致,既不会破坏线程内的程序顺序,也不会打破修改顺序的一致性。
为什么主流编译器不做这个优化?
主要有以下几个原因:
- 优化性价比极低:这种连续存储相同值的relaxed原子操作在实际代码中出现频率极低,编译器团队会优先投入资源到收益更大的常见优化(比如循环展开、死代码消除、函数内联等)。
- 原子操作的优化约束:编译器对原子操作的优化有严格的安全限制,要实现这种合并,需要额外开发逻辑检测“连续存储相同值的relaxed原子操作”,会增加编译器的复杂度,还容易引入语义bug。
- 硬件已兜底优化:在x86等主流架构下,现代CPU会在执行阶段自动合并这类冗余存储,两次
mov的实际执行开销和单次存储几乎无区别,编译器无需额外处理。 - 调试与可预测性:保留原始操作序列,能让开发者在调试时直观看到代码的原始意图,符合编译器“尽量保留用户代码行为可见性”的设计原则。
内容的提问来源于stack exchange,提问作者Jan Schultke
相关产品推荐
相关产品推荐

