std::atomic的load/store与memory_order详解
std::atomic::load()和store()在底层对应哪些CPU指令?不同memory_order参数(relaxed/consume/acquire/release/acq_rel/seq_cst)对编译器优化和CPU指令生成有什么影响?如何选择正确的内存序?
回答
孤独的心
x86上的指令生成:
- relaxed:普通mov指令(不阻止任何重排)
- acquire(load):普通mov指令(x86的读取自带acquire语义,不会将后续指令重排到加载前)
- release(store):普通mov指令(x86的写入自带release语义,不会将先前指令重排到写入后)
- seq_cst(store):
mov+mfence(或使用xchg指令,其自带锁语义) - seq_cst(load):普通mov
ARM上的差异:
- relaxed:普通ldr/str
- acquire(load):
ldar(Load-Acquire Register) - release(store):
stlr(Store-Release Register) - seq_cst:
dmb ish+ 普通指令,或特殊的ldar/stlr
含义: | memory_order | Load(读)效果 | Store(写)效果 | |-------------|-------------|-------------| | relaxed | 仅原子性,无顺序约束 | 仅原子性 | | consume | 控制依赖(已弃用,不建议用) | - | | acquire | 后续读写不能重排到此load之前 | - | | release | - | 先前读写不能重排到此store之后 | | acq_rel | 同acquire | 同release | | seq_cst | 全局顺序一致(最严格) | 全局顺序一致 |
选择指南:
- 只有计数器累加→relaxed
- 发布-获取模式(flag/数据发布)→acquire+release
- 默认:seq_cst(最简单正确,但x86上无额外开销,ARM上略有)
- 性能关键路径且理解内存模型→优化为更弱的order
- 不要使用consume(C++17已弃用,C++20无提升)
错误案例:用relaxed实现自旋锁错误(需要acquire/release)。