自旋锁 (SpinLock)

SpinLock<T> 是一个基于原子操作和中断屏蔽的互斥锁,用于保护在多核和抢占环境下被并发访问的共享数据。

源码链接: os/src/sync/spin_lock.rs

1. 工作原理

SpinLock 的核心机制结合了中断屏蔽和原子自旋,以应对两种并发来源:

  1. 本地核心中断: 在获取锁之前,SpinLock禁用当前CPU核心的中断。这可以防止在持有锁时,被一个中断处理程序打断,从而避免了当前任务与中断处理程序之间的竞争。
  2. 多核并发: SpinLock 内部使用一个 RawSpinLock,它依赖CPU的原子指令(如 amoswap)来实现互斥。如果另一个CPU核心已经持有了该锁,当前核心将在一个循环中“自旋”,不断尝试获取锁,直到成功为止。

当锁被释放时(通过 SpinLockGuarddrop),它会先释放原子锁,然后恢复之前的中断状态

2. 核心接口

  • pub fn new(data: T) -> Self: 创建一个新的 SpinLock,包裹需要保护的数据 data
  • pub fn lock(&self) -> SpinLockGuard<T>: 获取锁。此方法会阻塞(自旋),直到成功获取锁为止,并返回一个锁守卫 SpinLockGuard

3. 锁守卫 (SpinLockGuard)

SpinLockGuardSpinLock 安全性的关键。

  • 它通过实现 DerefDerefMut Trait,使得用户可以像直接访问裸指针一样方便地访问被保护的数据。
  • SpinLockGuard 离开作用域时,其 Drop 实现会自动调用 unlock(),释放锁并恢复中断,从而避免了忘记解锁导致的死锁。

4. 适用场景

优点:

  • 实现简单,开销小,获取锁和释放锁的速度非常快(如果锁未被争用)。

缺点:

  • 持锁等待期间会占用CPU时间进行空转(自旋),浪费CPU资源。
  • 严禁在持有 SpinLock 的情况下进行任何可能导致任务睡眠或调度的操作(如申请内存、等待I/O、获取 SleepLock),否则可能导致整个系统死锁。

结论: SpinLock 只适用于保护那些访问时间极短的临界区。如果临界区内的操作耗时较长,应使用 SleepLock