memory_order的核心逻辑是按需选择最弱的内存序:只需原子性时用relaxed,需同步时依“发布-获取”配对选release/acquire,读写兼具选acq_rel,仅全局顺序必需时才用seq_cst。

memory_order 的核心逻辑:按需选最弱的序
选内存序不是看“哪个更安全”,而是看“当前操作需要多强的同步保证”。越强的序(如 memory_order_seq_cst)性能开销越大,越弱的序(如 memory_order_relaxed)越快但不提供同步。关键原则是:**只在需要同步或依赖时才升级序,其余一律用 relaxed**。
五种 memory_order 的典型用途
memory_order_relaxed:仅保证原子性,不约束重排,不建立 happens-before 关系。
- 适合计数器、统计指标、引用计数(如 shared_ptr 内部)、flag 初始化等无需同步的场景。
- 示例:counter.fetch_add(1, memory_order_relaxed);
memory_order_acquire 和 memory_order_release:成对使用,构成“锁释放-获取”语义。
- release 写:确保该写之前的所有内存操作(读/写)不会被重排到它之后;
- acquire 读:确保该读之后的所有内存操作不会被重排到它之前;
- 它们一起让 release 前的操作对 acquire 后的操作可见(happens-before)。
- 典型用于自旋锁、无锁队列的 head/tail 更新、生产者-消费者 handoff。
memory_order_acq_rel:兼具 acquire 和 release,用于 read-modify-write 操作(如 fetch_or, compare_exchange_weak)。
- 既防止前面的读写重排到操作后,也防止后面的读写重排到操作前;
- 常见于带状态切换的原子标志位更新,比如把一个 flag 从 “pending” 改为 “done”,同时读取关联数据。
memory_order_seq_cst:默认序,最强一致性模型。
- 所有线程看到的原子操作顺序全局一致;
- 隐含 acquire + release + 全局顺序约束;
- 适合初学者、调试阶段、或真正需要严格顺序的场景(如实现互斥锁、信号量、或与 non-atomic 变量做简单同步);
- 性能代价最高,尤其在 ARM/AArch64 上可能插入 full barrier。
怎么选?三步判断法
red">第一步:这个原子操作是否要和其他内存访问建立同步关系?
- 否 → 用 relaxed;
- 是 → 进入第二步。
第二步:它是“发布数据”(写)还是“获取数据”(读)?
- 发布数据(如 store 到 flag 表示“数据已就绪”)→ 用 release;
- 获取数据(如 load flag 确认“数据可读”)→ 用 acquire;
- 既是发布又是获取(如 CAS 成功后修改状态并读取结果)→ 用 acq_rel。
第三步:是否需要跨多个原子变量维持统一顺序?
- 比如:线程 A 写 x(seq_cst),再写 y(seq_cst);线程 B 读 y(seq_cst) 后一定能看到 x 的新值 → 需要 seq_cst;
- 大多数业务代码不需要这种强保证,用 acquire/release 就够了。
常见误用和陷阱
- 混淆 acquire 和 release 的配对:必须是 release store 与 acquire load 配对,不能用 acquire store 或 release load(它们无意义,编译器可能报错或降级);
- 对 non-atomic 变量做 relaxed 操作后,错误认为“只要原子变量变了,其他变量也同步了”——这是错的,必须用 acquire/release 显式建立依赖;
- 在 x86 上过度依赖硬件强序:x86 默认有 acquire/release 效果,但代码移植到 ARM/PowerPC 会出错,必须靠 memory_order 显式表达意图;
- 把 compare_exchange_weak 的失败路径当作同步点:失败时不产生任何同步效果,不能靠它传递 happens-before。











