这是一个场景。假设某个内核任务在单处理器系统上运行且禁用了抢占功能。任务获得一个自旋锁。现在,它正在执行关键部分。此时,如果该任务可用的时间片到期并且必须将其排定,该怎么办?
spin_lock
有防止这种情况发生的机制吗?从内核代码中,我了解到spin_lock基本上是禁用了抢占的单处理器上的nop
。准确地说,它所做的只是barrier()
我知道为什么它是nop
(因为它是单处理器,并且没有其他任务可以在那一瞬间处理数据),但我仍然不知道如何将其不间断(由于IRQ或调度)。
我在这里想念什么?指向Linux内核代码的指针对此很有帮助。
我的基本假设:
32位Linux内核
答案 0 :(得分:1)
实际上,spin_lock()
通过在尝试获取锁之前调用preempt_disable()
来禁用抢占,因此情况#1,#2,#3永远不会发生。
spin_lock()从最近的源代码中最终调用__raw_spin_lock(),后者在调用preempt_disable()
来获取锁之前先调用spin_acquire()
。中断上下文中常用的spin_lock_irqsave()
具有相似的上下文。
关于#3,如果变量是在进程/中断上下文之间共享的,则应始终使用spin_lock_irq()/spin_lock_irqsave()
而不是spin_lock()
以避免死锁。
答案 1 :(得分:0)
处理时间片到期的机制是计时器中断。中断将为该进程设置TIF_NEEDS_RESCHED标志。从计时器的中断上下文返回到关键部分时,将检查是否由于TIF_NEEDS_RESCHED标志而抢占了该进程。由于禁用了抢占功能,因此什么也不会发生,它会返回到您的关键部分。
关键部分结束后,释放锁将调用preempt_enable()以重新启用抢占。在那一刻,再次检查是否要抢占。由于已设置TIF_NEEDS_RESCHED标志并启用了抢占功能,因此该进程将被抢占。
自旋锁在单元处理器系统上根本不存在,因为它们没有意义。如果不拥有锁的线程尝试获取该锁,则意味着拥有该锁的线程当前处于睡眠状态(只有一个cpu)。因此,没有理由旋转等待正在睡着的东西。因此,在这些情况下,自旋锁已被优化为仅可抢占禁用,因此没有其他线程可以触及关键部分。