std::atomic变量必须用load()/store()或原子操作符读写,不可直接赋值;初始化推荐{}语法;内存序按需选择relaxed/release-acquire/seq_cst;仅支持trivially copyable且尺寸适配的类型;compare_exchange_weak需循环重试。
atomic 的初始化和基本读写操作
直接用 std::atomic 声明变量后,不能像普通变量那样用 = 赋值或读取——它会编译失败。必须显式调用 load() 和 store(),或者用 operator++ 等重载接口(仅对整型、指针等特化类型可用)。
-
std::atomic<int> counter{0};</int>是安全的零初始化;但std::atomic<int> counter = 0;</int>在某些旧编译器上可能触发隐式转换警告 - 读取推荐用
counter.load(std::memory_order_relaxed),不加参数默认是seq_cst,开销大且常不必要 - 写入用
counter.store(42, std::memory_order_release),避免直接赋值counter = 42(虽能编译,但语义模糊,易误导) - 自增操作可直接写
++counter或counter.fetch_add(1),后者返回旧值,更利于无锁逻辑判断
memory_order 选哪个?别一上来就用 seq_cst
std::memory_order_seq_cst 是最严格、最慢的内存序,也是所有原子操作的默认值。但它在多数场景中属于“过度同步”——比如生产者只写、消费者只读的单向通信,release/acquire 就够了。
- 纯计数器累加(无依赖其他变量):用
relaxed即可,性能接近普通变量 - 标志位通知(如
ready_flag.store(true, release)配合ready_flag.load(acquire)):必须成对使用release/acquire,才能保证之前写的非原子数据对另一线程可见 - 需要全局顺序一致的多变量协同(如双链表插入+计数更新):才考虑
seq_cst,但要意识到它会强制刷新 store buffer,可能拖慢整个 core
哪些类型能塞进 atomic?别硬塞自定义结构体
std::atomic 只支持 平凡可复制(trivially copyable) 且 大小不超过平台最大原子宽度 的类型。x86-64 通常是 16 字节,但实际支持因编译器而异。