非preemtive linux内核上的spin_lock

时间:2010-07-30 14:42:22

标签: locking linux-kernel mutex spinlock

我在一个拥有1个CPU且非预先存在的Linux内核(2.6.x)的系统上看到,一个spin_lock调用相当于一个空调用,因此以这种方式实现。

我无法理解:它不应该相当于在互斥上睡一觉吗?即使在非preemtive内核上,中断处理程序仍然可能被执行,或者我可能会调用一个将原始线程置于休眠状态的函数。因此,如果将空的spin_lock调用实现为互斥锁,那么它就是“安全”的。

有没有我得不到的东西?

4 个答案:

答案 0 :(得分:6)

如果你在非抢占式内核上使用spin_lock()来屏蔽数据与中断处理程序,那么你就会死锁(在单处理器机器上)。

如果中断处理程序运行而其他内核代码持有锁,它将永远旋转,因为常规内核代码无法恢复并释放锁。

只有在锁定夹持器可以始终运行完毕时才能使用自旋锁。

中断处理程序可能需要的锁的解决方案是使用spin_lock_irqsave(),它会在保持自旋锁时禁用中断。使用1个cpu,没有中断处理程序可以运行,因此不会出现死锁。在smp上,中断处理程序可能会在另一个cpu上开始旋转,但由于持有锁的cpu不能被中断,锁最终会被释放。

答案 1 :(得分:6)

回答问题的两个部分:

  

即使在非内存内核上,中断处理程序仍然可以执行,例如......

spin_lock()不应该防止中断处理程序 - 只有用户上下文内核代码。 spin_lock_irqsave()是中断禁用版本,此不是非抢占式单处理器上的无操作。

  

...或者我可能会调用一个让原始线程进入睡眠状态的函数。

持有旋转锁时不允许睡觉。这是“原子调度”错误。如果你想睡觉,你必须使用互斥量(再次 - 这些不是非抢占式单处理器上的无操作)。

答案 2 :(得分:5)

来自«Linux设备驱动程序»,来自Jonathan Corbet,Alessandro Rubini和Greg Kroah-Hartman:

  

如果一个非抢占式单处理器系统曾经进入过旋转   锁,它会永远旋转;没有其他线程可以   获取CPU以释放锁(因为它无法屈服)。   正因为如此,单片机系统上的自旋锁操作没有   启用抢占被优化为什么也不做,除了   改变IRQ掩码状态的那些(在Linux中,那将是   spin_lock_irqsave())。因为先发制人,即使你永远不会   希望您的代码在SMP系统上运行,您仍然需要实现   正确锁定。

如果您对在中断上下文(硬件或软件)中运行的代码可以使用的自旋锁感兴趣,则必须使用禁用中断的spin_lock_*形式。如果在您进入关键部分时中断到达,则不会这样做会使系统死锁。

答案 3 :(得分:1)

根据定义,如果您使用的是非抢占式内核,则不会被抢占。如果你做自己的多任务处理,那不是内核的问题;那是你的问题。中断处理程序仍然可以执行,但它们不会导致上下文切换。