为什么拿着螺旋锁时不允许"睡觉"?

SHH*_*SHH 7 c synchronization sleep linux-kernel spinlock

可能重复:
为什么不能在抱着螺旋锁的情况下睡觉?

据我所知,自旋锁应该在短时间内使用,并且只能在代码中选择,例如中断处理程序,其中不允许休眠(抢占).

但是,我不知道为什么会出现这样的"规则",即拿着螺旋锁时根本不应该睡觉.我知道这不是推荐的做法(因为它对性能有害),但我认为没有理由为什么睡眠不应该被允许进入自旋锁.

获取信号量时无法保持自旋锁,因为在等待信号量时可能需要休眠,而且在持有自旋锁时无法入睡(来自Robert Love的"Linux内核开发").

我能看到的唯一原因是出于可移植性的原因,因为在单处理器中,自旋锁被实现为禁用中断,并且通过禁用中断,当然不允许休眠(但是休眠不会破坏SMP系统中的代码).

但我想知道我的推理是否正确或是否还有其他原因.

bdo*_*lan 14

有几个原因,至少在Linux中,不允许在自旋锁中睡觉:

  1. 如果线程A在自旋锁中休眠,然后线程B尝试获取相同的自旋锁,则单处理器系统将死锁.线程B将永远不会进入休眠状态(因为自动锁在A完成时没有唤醒B所需的等待名单),并且线程A永远不会有机会被唤醒.
  2. 自旋锁用于信号量正是因为它们更有效 - 只要你不长时间竞争.允许睡眠意味着您将有很长的争用时间,消除使用螺旋锁的所有好处.在这种情况下,只需使用信号量,您的系统就会更快.
  3. 通过额外禁用中断,自旋锁通常用于与中断处理程序同步.如果您进入中断处理程序,则无法使用此用例(您无法切换回线程以使其唤醒并完成其自旋锁定关键部分).

使用合适的工具做正确的工作 - 如果你需要睡觉,信号量和互斥量是你的朋友.

  • @SumitTrehan:好点.如果自旋锁不是调度程序本身必不可少的东西,并且线程B不在中断上下文中并且没有禁用中断或抢占,则最终线程B可以被抢占.但是,在linux中,当保持(或即将保持)自旋锁时,抢占总是被禁用.这是因为如果一个线程在没有运行的情况下持有一个自旋锁,那么其他线程会浪费很多时间在锁上旋转,并且中断处理程序可能会出现死锁.所以实际上线程B不会被抢占并且会死锁. (2认同)

Dig*_*oss 8

  • 实际上,您可以在禁用中断或其他类型的排除活动时休眠.如果不这样做,您正在睡觉的条件可能会因中断而改变状态,然后您就永远不会醒来.睡眠代码通常永远不会在没有提升优先级的情况下进入,或者在决定睡眠和上下文切换之间包含执行路径的某些其他关键部分.

  • 但对于自旋锁,睡眠是一种灾难,因为锁定设置.其他线程在击中时会旋转,直到你从睡眠中醒来它们才会停止旋转.与自旋锁中最坏情况下预期的一些旋转相比,这可能是永恒的,因为自旋锁只是为了同步对存储器位置的访问,它们不应该与上下文切换机制相互作用.

    (就此而言,每个其他线程最终都可能会击中自旋锁,然后你就会楔入整个系统每个核心的每个线程.)