std::atomic::load默认使用std::memory_order_seq_cst,但性能开销大;应根据同步需求选用acquire/release或relaxed;store()与operator=内存序不同;compare_exchange_weak需分别指定成功和失败的内存序。

std::atomic::load 默认用的是 std::memory_order_seq_cst
绝大多数情况下,load() 不传 order 参数,就等价于 load(std::memory_order_seq_cst)。这不是“最安全”的选择,而是 C++ 标准规定的默认行为:它强制所有线程看到的操作顺序全局一致,代价是可能触发全内存栅栏(full fence),在弱一致性架构(如 ARM、RISC-V)上开销明显。
如果你只是读一个标志位(比如 std::atomic<bool> ready</bool>),且写端用的是 store(true, std::memory_order_release),那读端用 load(std::memory_order_acquire) 就足够了——既保证数据可见性,又避免不必要同步开销。
- 不要默认以为 “seq_cst 就是必须的”,尤其在高频轮询或性能敏感路径中
-
std::memory_order_relaxed可用于计数器累加、统计类场景,但不能用于同步逻辑(比如等待某个状态) - 用
load()时若没指定 order,编译器不会报错,但可能掩盖同步漏洞
store() 和 operator= 的内存序行为不完全等价
store() 明确支持传入任意 std::memory_order,而 operator= 固定使用 std::memory_order_seq_cst。这意味着:
- 想用
std::memory_order_release发布数据(如写完data后设ready = true),必须写ready.store(true, std::memory_order_release),不能写ready = true -
operator=看起来简洁,但会隐式引入更强的顺序约束,可能拖慢性能,也容易让后续维护者误判同步意图 - 代码审查时,
store()和load()是信号:这里有意图地控制内存序;=和隐式转换则缺乏这种表达力
load() 配合 acquire、store() 配合 release 才构成同步对
单个 load(std::memory_order_acquire) 或 store(std::memory_order_release) 没有意义——它们必须成对出现,跨线程才能建立 happens-before 关系。
立即学习“C++免费学习笔记(深入)”;
典型模式:
// 线程 A(生产者)
data = 42; // 普通写
ready.store(true, std::memory_order_release); // release store
<p>// 线程 B(消费者)
while (!ready.load(std::memory_order_acquire)) { /<em> 等待 </em>/ } // acquire load
// 此处能安全读 data == 42</p>- release store 保证其之前的普通写(
data = 42)不会被重排到它之后 - acquire load 保证其之后的普通读(
data)不会被重排到它之前 - 两个操作通过同一个原子变量(
ready)关联,才构成同步点 - 如果读端用了
relaxed,即使写端是release,也不能保证看到data的新值
compare_exchange_weak 的 memory_order 参数要分两组传
compare_exchange_weak() 是 RMW 操作,它内部包含一次 load 和一次 store,所以需要两个内存序参数:
- 成功时的内存序(即 store 部分):第二个参数
success - 失败时的内存序(即 load 部分):第三个参数
failure
常见写法:
std::atomic<int> counter{0};
int expected = 0;
counter.compare_exchange_weak(expected, 1,
std::memory_order_acq_rel, // 成功:既是 acquire(读旧值)又是 release(写新值)
std::memory_order_acquire); // 失败:只做 acquire load
- 漏掉第三个参数会导致编译失败(不是默认值)
- 多数场景下,
failure用std::memory_order_acquire足够;success用std::memory_order_acq_rel可支持后续同步 - 别把两个参数都设成
relaxed——除非你清楚自己在放弃同步语义
实际写多线程代码时,最容易忽略的不是语法,而是“哪个操作和哪个操作构成同步对”。load() 和 store() 的内存序必须跨线程配对理解,而不是孤立看单个调用。


















