自旋锁 (SpinLock)
SpinLock<T> 是一个基于原子操作和中断屏蔽的互斥锁,用于保护在多核和抢占环境下被并发访问的共享数据。
源码链接: os/src/sync/spin_lock.rs
1. 工作原理
SpinLock 的核心机制结合了中断屏蔽和原子自旋,以应对两种并发来源:
- 本地核心中断: 在获取锁之前,
SpinLock会禁用当前CPU核心的中断。这可以防止在持有锁时,被一个中断处理程序打断,从而避免了当前任务与中断处理程序之间的竞争。 - 多核并发:
SpinLock内部使用一个RawSpinLock,它依赖CPU的原子指令(如amoswap)来实现互斥。如果另一个CPU核心已经持有了该锁,当前核心将在一个循环中“自旋”,不断尝试获取锁,直到成功为止。
当锁被释放时(通过 SpinLockGuard 的 drop),它会先释放原子锁,然后恢复之前的中断状态。
2. 核心接口
pub fn new(data: T) -> Self: 创建一个新的SpinLock,包裹需要保护的数据data。pub fn lock(&self) -> SpinLockGuard<T>: 获取锁。此方法会阻塞(自旋),直到成功获取锁为止,并返回一个锁守卫SpinLockGuard。
3. 锁守卫 (SpinLockGuard)
SpinLockGuard 是 SpinLock 安全性的关键。
- 它通过实现
Deref和DerefMutTrait,使得用户可以像直接访问裸指针一样方便地访问被保护的数据。 - 当
SpinLockGuard离开作用域时,其Drop实现会自动调用unlock(),释放锁并恢复中断,从而避免了忘记解锁导致的死锁。
4. 适用场景
优点:
- 实现简单,开销小,获取锁和释放锁的速度非常快(如果锁未被争用)。
缺点:
- 持锁等待期间会占用CPU时间进行空转(自旋),浪费CPU资源。
- 严禁在持有
SpinLock的情况下进行任何可能导致任务睡眠或调度的操作(如申请内存、等待I/O、获取SleepLock),否则可能导致整个系统死锁。
结论: SpinLock 只适用于保护那些访问时间极短的临界区。如果临界区内的操作耗时较长,应使用 SleepLock。