默认内存序为memory_order_seq_cst,最严格安全但性能开销大;乱改易致数据竞争,仅独立计数器可用relaxed;acquire/release须配对用于同步;weak版compare_exchange因伪失败更轻量,需循环使用;fence仅在混合原子与非原子变量时必要;volatile无同步语义,不可替代atomic。

atomic 的默认内存序为什么不能乱改
默认构造的 std::atomic 使用 memory_order_seq_cst,这是最严格也最安全的顺序。它保证所有线程看到的原子操作顺序一致,且与非原子内存访问形成全序。但代价是可能触发全局内存屏障(如 x86 上的 mfence),在高竞争场景下显著拖慢性能。
常见误操作是把所有 load()/store() 都改成 memory_order_relaxed,结果出现读到“过期值”或逻辑错乱——比如一个线程写完标志位和数据,另一个线程却先读到标志位 true,再读到未初始化的数据。
- 仅当变量完全独立(如计数器、统计指标),且不参与同步逻辑时,才可用
memory_order_relaxed -
memory_order_acquire和memory_order_release必须配对使用:前者用于读标志位,后者用于写标志位,构成“发布-获取”同步关系 - x86 架构下
acquire/release几乎无额外开销,但 ARM/AArch64 必须插入dmb指令,不可忽略
compare_exchange_weak 为什么比 compare_exchange_strong 更常用
compare_exchange_weak 允许伪失败(spurious failure):即使当前值匹配,也可能返回 false。这在某些硬件(如 ARM、旧版 x86)上由 LL/SC(Load-Link/Store-Conditional)机制导致,属于正常行为,不是 bug。
它比 compare_exchange_strong 更轻量,尤其在循环重试场景中性能更好。几乎所有无锁数据结构(如 lock-free stack、queue)都用 weak 版本配合 do-while 循环。
立即学习“C++免费学习笔记(深入)”;
- 必须在循环中使用:
do { ... } while (!a.compare_exchange_weak(expected, desired)); - 不要用
weak做一次性判断(比如“如果等于 X 就执行 Y”,不重试),否则可能跳过逻辑 -
strong版本适合单次尝试、且失败代价高(如需要回滚复杂状态)的场景,但极少遇到
atomic_thread_fence 什么时候真得用,而不是靠 atomic 操作自带的序
std::atomic_thread_fence 是独立于任何 atomic 变量的全局内存屏障,只约束当前线程的内存访问顺序。它不操作数据,只起“围栏”作用。绝大多数情况不需要它——atomic 带内存序参数已足够。
真正需要它的典型场景是:混合使用原子变量和普通变量,并需跨变量建立同步。例如,用一个 std::atomic 作为就绪标志,但实际数据存在普通 int 中:
// 线程 A
data = 42;
atomic_flag.store(true, std::memory_order_release);
// 线程 B
if (atomic_flag.load(std::memory_order_acquire)) {
// 此处 data 一定可见 —— 但前提是线程 A 的 data=42 不被重排到 store 之后
// 而 release/acquire 本身只约束 atomic_flag 的操作,不约束 data
// 所以线程 A 需要:
data = 42;
std::atomic_thread_fence(std::memory_order_release);
atomic_flag.store(true, std::memory_order_relaxed);
}
- 除非你在手动管理非原子变量的可见性,否则别碰
atomic_thread_fence -
memory_order_seq_cstfence 是最强的,但它会阻塞所有后续内存操作,慎用 - 编译器可能把普通变量访问优化掉或重排,fence 是告诉编译器“这里不能动”
std::atomic 和 volatile bool 的根本区别在哪
volatile 只禁用编译器优化(如缓存到寄存器),不提供任何线程同步语义;std::atomic 则同时禁止编译器重排 + 生成必要硬件屏障 + 提供原子读写保证。
用 volatile bool 实现“停止标志”在单核或简单场景下看似有效,但在多核、开启 O2 优化、或遇到 StoreBuffer(如 x86 的 store forwarding)时大概率失效。
- 哪怕只是做
while(!flag) {}这种轮询,也必须用std::atomic,且 load 建议至少用memory_order_acquire -
volatile在 C++ 并发中基本没用,除了映射硬件寄存器等极少数场景 - 注意:
std::atomic不一定编译成锁,多数平台用单条指令(如 x86 的lock xchg或mov+ barrier)










