释放一致性(release consistency, RC)
RC的核心观点是:使用 FENCE 围绕所有同步操作是多余的
- 同步获取 (acquire) 只需要一个后续的 FENCE,
- 同步释放 (release) 只需要一个前面的 FENCE。
对于表 5.4 的临界区示例,可以省略 FENCE F11、F14、F21 和 F24。让我们关注 "R11: release(lock)"。FENCE F13 很重要,因为它在锁释放之前对临界区的load (L1i) 和store (S1j) 进行排序。FENCE F14 可以省略,因为如果core C1 的后续内存操作(表中未显示)在释放 R11 之前执行,则没有问题。
RC 实际上允许这些后续操作早在临界区开始时就执行,而 XC 的 FENCE 不允许这样的排序。RC 提供了类似于 FENCE 的 ACQUIRE 和 RELEASE 操作,但仅在一个方向而不是像 FENCE 那样在两个方向上对内存访问进行排序。更一般地说,RC 只需要:
- ACQUIRE -> Load, Store (but not Load, Store -> ACQUIRE)
- Load, Store -> RELEASE (but not RELEASE -> Load, Store) and
- SC ordering of ACQUIREs and RELEASEs:
- ACQUIRE -> ACQUIRE
- ACQUIRE -> RELEASE
- RELEASE -> ACQUIRE, and
- RELEASE -> RELEASE
RISC-V 弱内存顺序 (RVWMO)
RISC-V 实现了一个内存模型 RVWMO(注1),它可以理解为释放一致性 (RC) 和 XC 的混合。
- 与 XC 类似,RVWMO 是根据全局内存顺序(所有内存操作的总顺序)定义的,并且具有 FENCE 指令的几种变体。
- 与 RC 类似,load和store可以携带注释 (annotation):load指令可以携带 ACQUIRE 注释,store指令可以携带 RELEASE 注释
- RMW 指令可以使用单独的 RELEASE、单独的ACQUIRE 或 RELEASE 和 ACQUIRE 两者一起进行注释。
RELEASE/ACQUIRE orderings
有两种类型的ACQUIRE annotations和RELEASE annotations
- ACQUIRE-RCpc / RELEASE-RCpc
- ACQUIRE-RCsc / RELEASE-RCsc
其中,pc指的是processor consistency, pc是TSO的前身,SC指的是Sequential Consistency;
LOAD两种都可以用,RMW只能用RCsc;
这两种annotations提供的order描述如下:
- ACQUIRE -> Load,Store (ACQUIRE refers to both ACQUIRE-RCsc and ACQUIRE-RCpc)
- Load,Store -> RELEASE (RELEASE refers to both RELEASE-RCsc and RELEASE-RCpc)
- RELEASE-RCsc -> ACQUIRE-RCsc
FENCEorderings.
RVWMO有几种FENCE指令:
- strong FENCE instruction, FENCE RW,RW;
- enforces the Load,Store !Load,Store orderings;
- non-trivial combinations:
- FENCE RW,W;
- FENCE R,RW,
- FENCE R,R;
- FENCE W,W;
- FENCE.TSO
这里面R代表load, W代表store,简单描述下上面部分指令的含义;
- FENCE R,R: 强制保证load/load的顺序;
- FENCE.TSO:强制保证load->load, Store->Store, Load->Store的顺序;
RVWMO的例子
S1 ->L1 is enforced in core C1 due to the former and S2 -> L2 is enforced in core C2 due to the latter. The combination, thus, ensures that both r1 and r2 cannot read 0.
Dependency-induced orderings.
RVWMO 在某些方面略强于 XC。地址、数据和控制相关性可以在 RVWMO 中引起内存顺序,但在 XC 中则不然。考虑表 5.12 中所示的示例。这里,core C1 向 data2 写入 NEW,然后设置指针指向 data2 的位置。(通过 FENCE W, W 指令对两个store S1 和 S2 进行排序)。在core C2 中,L1 将指针的值load到 r1 中,然后load L2 解引用 (dereference) r1。尽管两个load L1 和 L2 没有明确排序,但 RVWMO 隐式强制执行 L1 -> L2,因为 L1 和 L2 之间存在地址依赖 (address dependency):L1 产生的值被 L2 解引用。
考虑表 5.13 中显示的示例,也称为load缓冲 (load buffering)。让我们假设 x 和 y 最初都是 0。可以允许 r1 和 r2 凭空读取任意值(比如 42)吗?有点令人惊讶的是,XC 并不禁止这种行为。因为在 L1 和 S1 以及 L2 和 S2 之间都没有 FENCE,所以 XC 不会强制任何一个 Load -> Store 顺序。这可能会导致执行以下操作:
- S1 预测 L1 将读取 42,然后推测性地将 42 写入 y,
- L2 从 y 读取 42 到 r2,
- S2 将 42 写入 x,并且
- L1 将 42 从 x 读入 r1,从而使初始预测“正确”。
然而,RVWMO 通过隐式强制 Load -> Store 顺序 (L1 -> S1 和 L2 -> S2) 来禁止这种行为,因为每个load和store之间存在数据依赖 (data dependency) 关系:每个load读取的值由接下来的store写入。
与此类似,RVWMO 还隐式地强制在load和后续store之间进行排序,该store控制依赖 (control dependent) 于load。
Same address orderings.
与 XC 一样,RVWMO 也强制执行
- Load -> Store ordering to the same address,
- Store -> Store ordering to the same address, and does not enforce
- Store -> Load ordering to the same address.
与 XC 不同,RVWMO 不强制
- Load -> Load ordering to the same address in all situations
仅在以下情况下才会强制执行:
(a) 两次load之间没有store到同一地址,以及
(b) 两次load返回由不同store写入的值。对于这种微妙的基本原理的详细讨论,读者可以参考 RISC-V 规范 [31]。
RISC-V 支持两种类型的 RMW
原子内存操作 (AMO) 和保留load/条件store (LdR/StC)。
虽然 AMO 来自单个指令(例如,fetch-and-increment),但 LdR/StC 实际上由两个单独的指令组成:LdR 带来一个值并为core做一个保留记号,而 StC 只有在保留记号仍然存在时才能成功。这两种 RMW 的原子性语义略有不同。与 XC RMW 类似,如果load和store在全局内存顺序中连续 (consecutively) 出现,则称 AMO 是原子的。LdR/StC 较弱。 假设 LdR 读取了 store s 产生的值;只要在全局内存顺序中 s 和 StC 之间没有相同地址的store,就可以说 LdR/StC 是原子的。
总而言之,RVWMO 是一种结合了 XC 和 RC 方面的最新宽松内存模型。对于详细的提议和正式规范,读者可以参考 RISC-V 规范。