禁用/启用中断是否需要内存屏障或类似内存排序约束?
问题解答
核心结论
在RISC-V架构下操作mstatus/sstatus禁用中断后,与后续自旋锁的RMW操作之间,通常不需要额外的硬件内存屏障,但必须添加编译器屏障来阻止编译器乱序优化。
1. RISC-V对CSR操作的固有硬件排序约束
根据RISC-V特权架构规范,修改mstatus/sstatus这类CSR寄存器的指令(如csrrw、csrci)本身具备强顺序性:
- 程序顺序中,CSR指令会等待所有前置内存操作完成后才执行;
- CSR指令执行完毕后,才会启动后续的内存操作。
硬件层面绝对不会将CSR修改指令与后续自旋锁的RMW操作(如compare_exchange对应的amoswap/amoor指令)重排序,因此不需要额外添加fence w,w这类硬件屏障。
2. 编译器层面的重排风险与解决
编译器无法感知CSR操作的副作用(中断禁用会直接影响线程执行逻辑),可能会将后续的自旋锁RMW操作重排到CSR修改之前,进而引发死锁。解决方式是添加编译器屏障:
- 可以在CSR操作的内联汇编中加入
"memory"clobber,例如修改sstatus禁用中断的代码:__asm__ volatile("csrci sstatus, %0" : : "i"(SSTATUS_SIE) : "memory"); - 或者单独插入编译器屏障:
__asm__ volatile("" : : : "memory");
这会告知编译器,此处内存状态已被外部修改,不能随意重排前后的内存操作。
3. 关于内存序的选择
不需要将自旋锁compare_exchange_weak_explicit的内存序从memory_order_acquire改为memory_order_acq_rel:
memory_order_acquire成功时的存储部分为memory_order_relaxed,但得益于RISC-V硬件对CSR操作的强排序约束,该relaxed存储不会与之前的CSR修改乱序;- 自旋锁的
acquire语义已经足够保证锁获取后的内存可见性,额外的release语义属于冗余操作。
内容的提问来源于stack exchange,提问作者usb_naming_is_confusing
相关产品推荐
相关产品推荐

