std::atomic 不支持直接赋值和拷贝构造,必须用构造函数或 .store() 初始化,读写需 .load()/.store(),自增用 .fetch_add(),memory_order 影响正确性与性能,atomic_flag 才保证 lock-free 且专用于自旋锁,compare_exchange_weak 需循环重试。

std::atomic 不能直接赋值或拷贝
声明为 std::atomic 的变量不支持普通变量那样的赋值和拷贝构造,比如 std::atomic<int> a = 5;</int> 看似合法,但其实是调用隐式转换构造函数;而 std::atomic<int> b = a;</int> 会编译失败——因为拷贝构造被显式删除了。
- 正确初始化:用构造函数或
.store(),例如std::atomic<int> x{42};</int>或std::atomic<int> y; y.store(42);</int> - 读取值必须用
.load(),不能写int z = y;(编译不过) - 写入值必须用
.store(),不能写y = 100;(同样编译不过) - 自增/自减要用
.fetch_add()、.fetch_sub(),而不是++y(虽部分特化支持,但语义和内存序易误用)
memory_order 参数不是可有可无的装饰
所有原子操作(load、store、exchange、compare_exchange_weak 等)都接受一个 memory_order 参数,默认是 std::memory_order_seq_cst。它直接影响性能和正确性,不是“先用默认,以后再优化”的选项。
-
std::memory_order_relaxed:仅保证该操作本身原子,不约束前后指令重排——适合计数器、标志位等无依赖场景 -
std::memory_order_acquire+std::memory_order_release配对使用,可建立线程间同步(如锁、信号量模拟),比seq_cst轻量 - 混用错误会导致数据竞争或看似随机的读写失效,例如用
relaxedstore 和acquireload 无法构成同步关系 - 调试时加
-fsanitize=thread能捕获部分 memory_order 误用,但不能替代逻辑设计
std::atomic 和 std::atomic_flag 是两回事
std::atomic<bool></bool> 支持 load/store,但不是 lock-free;而 std::atomic_flag 是 C++ 唯一保证 lock-free 的原子类型,且只提供 .test_and_set() 和 .clear(),专为自旋锁设计。
- 别用
std::atomic<bool></bool>实现自旋锁——它可能退化为内部互斥锁,失去原子性优势 -
std::atomic_flag必须用ATOMIC_FLAG_INIT初始化(C++17 起可默认构造),且不能拷贝、不能 load/store - 常见误写:
if (flag.load()) { flag.clear(); }—— 这不是原子操作,应改用flag.test_and_set(std::memory_order_acquire) - 检查是否 lock-free:调用
.is_lock_free(),在关键路径上建议静态断言static_assert(std::atomic_flag::is_always_lock_free);
compare_exchange_weak 和 compare_exchange_strong 的区别不只是性能
两者都实现 CAS(Compare-And-Swap),但 weak 版本允许“虚假失败”(spurious failure):即使当前值匹配,也可能返回 false。这不是 bug,而是某些架构(如 ARM、旧 x86)的硬件限制。
- 循环中必须用
weak+ while 循环,例如:int expected = x.load(); do { int desired = expected * 2; } while (!x.compare_exchange_weak(expected, desired)); -
strong版本在 x86 上通常编译为相同指令,但在 ARM 上开销更大;除非你明确需要单次尝试语义(如无循环上下文),否则优先选weak - 注意
expected是输入输出参数:失败时会被更新为当前实际值,所以循环中不用手动 reload - 如果操作涉及非平凡类型(如
std::atomic<:shared_ptr>></:shared_ptr>),weak更可能失败,需预留重试逻辑
用 std::atomic 不是加个模板就完事——内存序选择、操作方式、类型限制,每一步都得对得上场景。最常被忽略的是:把 std::atomic<t></t> 当普通变量用,或者默认用 seq_cst 却没意识到它在弱一致性架构上的开销。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











