从 Store Buffer 与 Invalidate Queue 理解 C++ 内存序

多核程序最难理解的地方,不是“多个线程同时执行”,而是不同核心可能以不同时间、不同顺序观察到内存操作。C++ 原子内存序就是程序员与编译器、处理器之间的约定:哪些重排被允许,哪些读写必须建立跨线程的先后关系。 本文重点解释四种常见内存序:relaxed、release、acquire 和 seq_cst,并把它们与 CPU 中的 Store Buffer、Invalidate Queue 联系起来。先给出结论: relaxed 只保证单次原子访问不可分割,不负责发布其他数据; release 用于发布,保证它前面的操作不会越过发布点跑到后面; acquire 用于接收,保证它后面的操作不会越过接收点跑到前面; 当 acquire 读到 release 写入的值时,两线程之间建立 synchronizes-with,进而形成 happens-before; seq_cst 在 acquire/release 的基础上,再要求所有 seq_cst 操作进入一个全局一致的单一顺序。 1. 为什么原子性还不够 看一个典型的消息发布程序: #include <atomic> #include <cassert> int payload = 0; std::atomic<bool> ready{false}; void producer() { payload = 42; ready.store(true, std::memory_order_release); } void consumer() { while (!ready.load(std::memory_order_acquire)) { } assert(payload == 42); } payload 不是原子变量,但这个程序没有数据竞争。原因不是 ready 本身具有原子性,而是 release/acquire 建立了下面这条关系链: producer consumer payload = 42 │ sequenced-before ▲ ▼ │ happens-before ready.store(true, release) ─ synchronizes-with ─> ready.load(acquire) │ sequenced-before ▼ read payload 如果 acquire load 读到了 release store 写入的 true,那么 release 之前的操作 happens-before acquire 之后的操作。因此 consumer 看到 ready == true 后,也必须看到此前发布的 payload == 42。 ...

2026年9月1日 · 3 分钟 · Hellokitty