memory_order 是原子操作的内存序约束,指定读写重排边界,非锁亦非同步点;需成对使用 acquire-release 等组合建立 happens-before,单侧设置无效。

memory_order 是什么,不是什么
memory_order 不是锁,也不是同步点本身,它只是告诉编译器和 CPU:“这条原子操作的读写,**在什么范围内允许重排**”。它不保证其他非原子变量的可见性,也不自动建立 happens-before 关系——必须成对使用(比如一个 store 配一个 load),且顺序要匹配,否则屏障无效。
常见误用:只在单侧加 memory_order_acquire,另一侧仍是默认 memory_order_seq_cst 或更弱,结果依赖关系断裂,读到陈旧值。
最常用四组 memory_order 组合的实际效果
真正影响执行行为的是「成对操作」的约束组合,不是单个枚举值:
-
memory_order_relaxed:仅保证原子性,不参与同步。适合计数器、引用计数递增等无需顺序语义的场景 -
memory_order_acquire+memory_order_release:构成“获取-释放”同步。写端用release,读端用acquire,可让该原子操作之前/之后的内存访问分别不被重排到其后/前——这是实现无锁队列、双检查锁(DCLP)的关键 -
memory_order_acquire+memory_order_consume:已基本弃用(C++20 中标记为 deprecated),因数据依赖链难以静态分析,编译器难优化,且多数架构上与acquire等价 -
memory_order_seq_cst:全局顺序一致。所有线程看到同一套原子操作执行顺序。性能开销最大(尤其在 ARM/PowerPC 上需显式DMB指令),但语义最直观,调试友好
底层汇编和硬件指令怎么对应
不同平台生成的屏障指令差异很大,不能假设 acquire 总是插入 lfence:
立即学习“C++免费学习笔记(深入)”;
- x86-64:
acquire/release基本不生成额外指令(靠 x86 的强内存模型保证),seq_cststore 会加mfence或xchg(后者隐含全屏障) - ARM64:
acquire编译为ldar,release为stlr,seq_cst则需配对dsb sy - RISC-V:
acquire对应lr.w a0, (a1)+fence r,rw,release对应sc.w a0, a2, (a1)+fence rw,w
所以写跨平台无锁代码时,别硬编码汇编屏障;靠 std::atomic 的 memory_order 让编译器按目标平台选最轻量指令。
为什么 std::atomic_thread_fence 不如原子操作自带的 order 灵活
std::atomic_thread_fence 是“全局屏障”,作用于所有内存访问,粒度粗、开销大、易误用:
- 它不绑定到某个原子变量,无法表达“仅对这个 flag 的读写建立同步”,容易过度限制,拖慢性能
- 和普通原子操作混用时,容易漏掉配对:比如写了
atomic_thread_fence(acquire),却忘了后续load本身也要用memory_order_acquire(否则 fence 无效) - 现代 C++ 实践中,95% 的场景直接用带
memory_order的load()/store()/exchange()就够了;fence仅用于极少数需要“对非原子变量批量建序”的场合(如 lock-free ring buffer 的索引更新后批量刷新数据数组)
真正难的从来不是记住六个枚举值,而是判断哪两个操作之间存在逻辑依赖,并选择能恰好封住重排漏洞、又不额外拖慢的那一对 order。









