引言
在处理器架构领域,RISC-V 作为开源指令集架构(ISA)的新星,正在从嵌入式系统向高性能计算、服务器和 AI 芯片领域快速渗透。与 x86 和 ARM 不同,RISC-V 采用了弱内存模型(Weak Memory Model)设计——也就是 RISC-V Weak Memory Order(RVWMO)。这一设计赋予了硬件实现更大的自由度,但也给系统软件开发者带来了全新的挑战。
本文将深入剖析 RISC-V 弱内存模型的核心原理,探讨其与 ARM 弱内存模型的异同,并通过实际代码示例展示如何在 RISC-V 平台上编写正确的并发代码。
一、为什么需要弱内存模型?
在现代乱序执行(Out-of-Order)处理器中,内存访问的实际执行顺序与程序指定的顺序可能不同。这种重排(reordering)是性能优化的重要手段: Store Buffer、Load Buffer、缓存一致性协议等硬件优化都可能引入内存顺序的放松。
强内存模型(如 x86-TSO)要求几乎所有内存操作按序执行,限制了硬件优化空间。弱内存模型则允许更多重排,只要求程序员通过 Fence 指令显式指定需要保序的访问对。
四种基本重排
在弱内存模型中,需要关注以下四种可能的重排情况:
| 重排类型 | 原始顺序 | 可能被重排为 | 缩写 |
|---|---|---|---|
| Load-Load | L1 → L2 | L2 → L1 | LL |
| Load-Store | L → S | S → L | LS |
| Store-Load | S → L | L → S | SL |
| Store-Store | S1 → S2 | S2 → S1 | SS |
ARMv7/v8 允许全部四种重排;RISC-V RVWMO 同样允许全部四种重排,但通过 fence 指令提供精细控制。
二、RISC-V RVWMO 核心规则
RVWMO(RISC-V Weak Memory Ordering)的核心原则可以用以下规则概括:
2.1 程序顺序(Program Order)与全局内存顺序
程序顺序(po)指单个 hart(硬件线程)中指令在 ISA 层面的顺序。全局内存顺序(gmo)指所有内存操作在所有 hart 上达成的全局可见顺序。RVWMO 要求:同一 hart 内的 store 操作按程序顺序对其他 hart 全局可见——但这不意味着 load 也会按此顺序观察到。
2.2 保序关系(Preserved Program Order, PPO)
并非所有程序顺序都会被保留。RVWMO 定义了哪些序对是被"保留"的(即不会被重排),主要包括:
- 地址依赖(Address Dependency): 当后续 load 的地址依赖于前一条 load 的结果时,这两者不会重排
- 数据依赖(Data Dependency): 后续 store 的数据依赖于前一条 load 的结果时
- 控制依赖(Control Dependency): 通过分支指令建立的序关系
- 同一地址的访问: 对同一地址的 load 和 store 按序执行
- 显式 Fence: fence 指令前后不会被跨越
2.3 FENCE 指令详解
RISC-V 的 fence 指令提供了精细的保序控制:
fence rw, rw // 全屏障: StoreLoad + Store-Store + Load-Store + Load-Load
fence r, r // Load-Load 屏障
fence w, w // Store-Store 屏障
fence r, w // Load-Store 屏障
fence w, r // StoreLoad 屏障
fence.tso // TSO 模式屏障(RISC-V 特有)
三、RISC-V 与 ARM 弱内存模型的对比
| 特性 | ARMv8 (ARM) | RISC-V RVWMO |
|---|---|---|
| 基础模型 | 允许全部四种重排 | 允许全部四种重排 |
| 屏障指令 | DMB/DSB/ISB | FENCE / FENCE.I / FENCE.TSO |
| 地址依赖保留 | 是 | 是 |
| 控制依赖保留 | 有限(仅特定场景) | 是 |
| Atomic 扩展 | LSE, LDAPR | A 扩展(LR/SC + AMO) |
| Load-Acquire | LDAPR/LDAR | 带 aq 位的 AMO/LR |
| Store-Release | STLR/STLRB | 带 rl 位的 AMO/SC |
| 屏障哲学 | 按领域封装屏障指令 | 按位组合定义细粒度屏障 |
四、RISC-V 原子操作与 acquire/release 语义
RISC-V A(Atomic)扩展提供两类原子原语:保留加载/条件存储(LR/SC)和原子内存操作(AMO),两者均支持 acquire/release 标记位:
4.1 LR/SC 与 AMO 的 aq/rl 位
// 带 acquire 的加载: 后续内存操作不会被重排到之前
lr.aq t0, (a0) // Load Reserved with Acquire
// 带 release 的存储: 前面内存操作不会被重排到之后
sc.rl t1, t2, (a0) // Store Conditional with Release
4.2 C++ Memory Mapping
// C++ memory_order → RISC-V 指令映射
// memory_order_relaxed → 普通 load/store
// memory_order_acquire → fence r,rw / lr.aq
// memory_order_release → fence rw,w / sc.rl
// memory_order_acq_rel → fence rw,rw
// memory_order_seq_cst → 全屏障 (最强一致性)
五、经典并发模式在 RISC-V 上的实现
5.1 消息传递(Message Passing)
// 线程 A(生产者)
data = 42;
atomic_store(&flag, 1, release); // store-release
// 线程 B(消费者)
while (atomic_load(&flag, acquire) != 1); // load-acquire
assert(data == 42); // 保证看到 data = 42
5.2 Lock-based 互斥锁
// 加锁: amoswap.aq - 原子交换+acquire
lock:
li t1, 1
1: amoswap.aq t0, t1, (a0)
bnez t0, 1b
// 临界区...
// 解锁: amoswap.rl - 原子交换+release
unlock:
amoswap.rl x0, x0, (a0)
5.3 Dekker 算法
// Thread 0 | // Thread 1
flag0 = 1; | flag1 = 1;
fence w, r | fence w, r // 关键屏障!
if (flag1 == 0) { | if (flag0 == 0) {
// 进入临界区 | // 进入临界区
} | }
六、性能考量与最佳实践
- 优先使用 acquire/release 语义:比 seq_cst 少一条全屏障指令,性能更好
- 避免不必要的 StoreLoad 屏障:fence w,r 是开销最大的屏障,仅 Store-Load 跨 hart 依赖时使用
- 利用地址依赖性:依赖关系天然保序无需额外屏障,如 ptr->data 与 ptr->next
- 使用 C/C++ 抽象层:C11 <stdatomic.h> 和 C++11 <atomic> 已正确映射到 RISC-V
七、RISC-V 内存模型的发展
- FENCE.TSO:TSO 屏障,兼容 x86 代码迁移
- Ztso 扩展:硬件层面 TSO 模式支持
- Zacas 扩展:提供 CAS 原子操作,增强跨平台兼容性
八、总结
RISC-V RVWMO 的设计哲学是「给硬件最大自由,给程序员细粒度控制」。它不像 ARM 那样封装高层屏障指令,也不是像 x86 那样的模型化 TSO,而是提供一套灵活的组合规则。这种设计让 RISC-V 在嵌入式(简单实现)和高端处理器(激进乱序)之间都能有优秀的实现空间。
理解 RVWMO 对于 RISC-V 系统软件开发至关重要——无论你是编写操作系统内核、驱动程序、运行时还是高性能并发应用,都需要在「性能」与「正确性」之间找到最佳平衡点。
参考资源
- RISC-V Unprivileged Specification - Section 14 (Memory Model)
- Waterman, A., & Asanović, K. (2019). The RISC-V Instruction Set Manual, Volume I
- Maranget, L., Sarkar, S., & Sewell, P. (2012). A Tutorial Introduction to ARM and POWER Relaxed Memory Models

发表评论 取消回复