0

这是一个场景。假设内核任务在禁用抢占的单处理器系统上运行。该任务获得自旋锁。现在它正在执行它的关键部分。这个时候,如果这个任务可用的时间片过期了,又要被调度出去怎么办?

  1. 是否spin_lock有防止这种情况发生的机制?
  2. 可以排期吗?如果是,那么临界区会发生什么?
  3. 它可以被 IRQ 中断吗?(假设禁用抢占)
  4. 这种情况可行吗?换句话说,这种情况会发生吗?

从内核代码中,我了解到 spin_lock 基本上是nop在禁用抢占的单处理器上。准确地说,它所做的只是barrier() 我理解它为什么是一个nop(因为它是一个单处理器,并且在那一刻没有其他任务可以处理数据)但我仍然不明白它是如何不间断的(由于 IRQ 或调度)。我在这里想念什么?指向表明这一点的 Linux 内核代码的指针可能真的很有帮助。

我的基本假设:

32 位 Linux 内核

4

2 回答 2

1

实际上通过在尝试获取锁之前spin_lock()调用来禁用抢占,因此场景#1、#2、#3 永远不会发生。preempt_disable()从最近的源代码来看,spin_lock()最终调用__raw_spin_lock(),它在调用preempt_disable()之前调用spin_acquire()以获取锁。spin_lock_irqsave()中断上下文中常用的有类似的上下文。

关于#3,如果变量在进程/中断上下文之间共享,则应始终使用spin_lock_irq()/spin_lock_irqsave()而不是spin_lock()避免死锁情况。

于 2019-01-25T05:24:40.747 回答
0

处理时间片到期的机制是定时器中断。中断将为进程设置 TIF_NEEDS_RESCHED 标志。当从定时器的中断上下文返回到临界区时,将检查是否由于 TIF_NEEDS_RESCHED 标志而抢占进程。由于禁用了抢占,所以什么都不会发生,它将返回到您的关键部分。

当您的临界区结束时,锁的释放将调用 preempt_enable() 以重新启用抢占。在那一刻,对是否抢占进行另一次检查。由于设置了 TIF_NEEDS_RESCHED 标志并且现在启用了抢占,因此该进程将被抢占。

  1. 自旋锁禁用抢占。
  2. 不,因为抢占已禁用。
  3. 是的。有一些自旋锁版本可以禁用 IRQ 来防止这种情况。
  4. 否,因为自旋锁禁用抢占。

无论如何,自旋锁在单元处理器系统上都不存在,因为它们没有意义。如果一个不拥有锁的线程试图获取它,这意味着拥有它的线程当前处于休眠状态(只有一个 cpu)。所以没有理由旋转等待睡着的东西。出于这个原因,在这些情况下,自旋锁被优化为只是抢占禁用,因此没有其他线程可以触及临界区。

于 2020-09-17T15:19:06.103 回答