基础能力系列 - 多线程1 - 内存序
C++11 定义了 6 种原子操作的内存序(memory order),用于控制多线程中的可见性和重排序规则。如下是六种内存序的简介、特点和适用场景:
六种内存序一览表
| 内存序名称 | 描述 / 特点 | 是否同步其他线程可见性 | 是否禁止重排序 | 使用场景示例 |
|---|---|---|---|---|
memory_order_relaxed | 最弱序,无同步,无重排序限制 | 不同步其他线程 | 允许重排序 | 统计计数器、自增编号等 |
memory_order_consume | 数据依赖同步(已废弃) | 实际等同 acquire | 编译器优化误差多 | 几乎不用 |
memory_order_acquire | 获取操作,防止之后操作被重排序到前面 | 同步前写可见 | 禁止之后操作重排序 | load时读取同步数据 |
memory_order_release | 释放操作,防止之前操作被重排序到后面 | 同步后读可见 | 禁止之前操作重排序 | store时写入同步数据 |
memory_order_acq_rel | 同时具有 acquire 和 release 效果 | 双向同步 | 全部禁止重排序 | 常用于fetch_add等读改写操作 |
memory_order_seq_cst | 最强序,全局顺序一致性 | 所有线程可见 | 强制全局顺序 | 多线程安全,易理解但性能最低 |
实用说明
memory_order_relaxed`
- 不做任何同步,仅保证原子性。
- 不保证其他线程看到值变化的顺序。
std::atomic<int>x(0);x.store(1,std::memory_order_relaxed);// 线程B可能看不到memory_order_acquire`
- 常用于
load操作。 - 保证:本线程对该变量之后的操作不会被提到它前面。
intdata=0;std::atomic<bool>ready=false;// 线程Adata=42;ready.store(true,std::memory_order_release);// 线程Bwhile(!ready.load(std::memory_order_acquire));std::cout<<data;// 始终能看到 data = 42memory_order_release`
- 常用于
store操作。 - 保证:本线程在此之前的写入对其他 acquire 线程可见。
memory_order_acq_rel`
- 用于读-改-写原子操作:如
fetch_add、compare_exchange - 保证:在操作前后都不能乱序
counter.fetch_add(1,std::memory_order_acq_rel);memory_order_seq_cst`
- “Sequential Consistency”:最直观的并发语义
- 保证所有线程看到的修改具有全局一致顺序
- 对于简单并发程序是最安全选择,但性能可能不理想
memory_order_consume`
- 理论上只依赖“数据依赖性”,但已在实践中废弃(比如 gcc/clang 实际当作 acquire 处理)
小结
Relaxed < Acquire/Release < Acq_Rel < Seq_Cst (低同步/快) → (高同步/慢)- 往期精彩回顾:
- 基础能力系列
- 区块链知识系列
- 密码学系列
- 零知识证明系列
- 共识系列
- 公链调研系列
- BTC系列
- 以太坊系列
- EOS系列
- Filecoin系列
- 联盟链系列
- Fabric系列
- 智能合约系列
- Token系列
