Memory-Ordering与屏障
现代 CPU 为了性能,会乱序执行 (Out-of-order Execution) 指令;编译器也会为了优化而重排指令。
危机
在 acquire 函数中:
- 锁变量设为 1 (Locked)。
- 临界区代码 (读写共享数据)。
如果 CPU/编译器 认为这两步没有数据依赖,可能会优化成:
- 临界区代码 (先执行!)。
- 锁变量设为 1。
后果: 你还没锁门,就把家里的东西搬出来了。其他 CPU 会看到未受保护的数据。
解决方案: Memory Barrier
__sync_synchronize() (RISC-V 的 fence 指令)。
- 语义: 屏障之前的所有内存操作,必须在屏障之后的操作开始之前完成。
- xv6 在
acquire拿到锁之后、release释放锁之前,都加了屏障,强行通过串行化保证逻辑正确。