aq (acquire, 获取) 和 rl (release, 释放) 是 RISC-V 原子指令的可选后缀,用于精确控制内存访问的顺序 ,以保证多核间的同步正确性。它们比使用单独的 FENCE 指令更高效。

默认的 RVWMO 内存模型允许 CPU 和编译器重排内存访问以优化性能。但在多核同步时(例如获取锁、释放锁),必须保证某些顺序不被破坏:
-
获取锁 :锁内的读/写不能被移到获取锁操作之前。
-
释放锁 :锁内的读/写不能被移到释放锁操作之后。
.aq/.rl 以更细粒度的方式提供这些保证,避免了用 FENCE 指令产生全局"全副武装"的性能开销。
限制
aq/rl是内存顺序标志,用来控制该内存操作与其他内存操作之间的可见性顺序,因此只对有内存访问的指令有意义。- 非内存指令(如算术、逻辑、分支)不涉及内存访问顺序,无法附加这些标志。

示例
假设程序顺序:... [指令A] ... [带.aq的指令] ... [中间指令序列] ... [带.rl的指令] ... [指令B] ...
那么问:
-
aq之前的指令(即指令A)可以重排到aq/rl之间的内存访问之后吗?即可以越过.aq指令,进入中间区域吗?
-
可以。
-
.aq只保证:该指令之后的所有内存访问 (即中间区域内的内存访问)不会重排到该指令之前。 -
它不阻止 该指令之前 的内存访问(即指令 A 中的内存访问)重排到该指令之后。
-
因此,指令 A 中的内存访问完全可以穿越
.aq指令,进入中间区域(甚至在.rl之后也可能,但这里只问"之间")。
-
-
-
rl之后的指令(即指令B)可以重排到aq/rl之间的内存指令之前吗?即可以越过.rl指令,进入中间区域吗?
-
可以
-
.rl只保证:该指令之前的所有内存访问 (包括中间区域内的内存访问)不会重排到该指令之后。 -
它不阻止 该指令之后 的内存访问(即指令 B 中的内存访问)重排到该指令之前。
-
因此,指令 B 中的内存访问完全可以穿越
.rl指令,进入中间区域(甚至跑到.aq之前也可能,但这里只问"之间")。
-
-
-
rl之后的内存访问,能重拍到aq之前吗?
-
不能
-
.rl的作用 :允许其之后的内存操作(指令 B)向前重排,但最多只能越过.rl本身,不能无视其他屏障。 -
.aq的作用 :禁止其之后的任何内存操作(包括指令 B)重排到它之前。因为指令 B 在程序顺序中位于.aq之后,所以它绝对不能 出现在.aq之前。 -
因此,即使
.rl允许指令 B 向前重排到.rl之前,它依然被.aq的"单向墙"挡住,无法再继续向前越过.aq。
-
-
-
aq之前的内存访问,能重排到rl之后吗?
- 不能,原因同上;