Emi*_*ano 4 mutex locking linux-kernel spinlock
我在一个具有1个CPU和非预处理Linux内核(2.6.x)的系统上读到,spin_lock调用相当于一个空调用,因此以这种方式实现.
我无法理解:它不应该相当于在互斥上睡一觉吗?即使在非preemtive内核上,中断处理程序仍然可能被执行,或者我可能会调用一个将原始线程置于休眠状态的函数.因此,空的spin_lock调用是"安全的"并不是真的,如果它被实现为互斥锁的话.
有没有我得不到的东西?
如果您要spin_lock()在非抢占式内核上使用屏蔽数据以防止中断处理程序,则会出现死锁(在单处理器计算机上).
如果中断处理程序运行而其他内核代码持有锁,它将永远旋转,因为常规内核代码无法恢复并释放锁.
只有在锁定器可以始终运行完成时才能使用自旋锁.
中断处理程序可能需要的锁的解决方案是使用spin_lock_irqsave(),它在保持自旋锁时禁用中断.使用1个cpu,没有中断处理程序可以运行,因此不会出现死锁.在smp上,中断处理程序可能会在另一个cpu上开始旋转,但由于持有锁的cpu不能被中断,最终会释放锁.
要回答你问题的两个部分:
即使在非preemtive内核上,中断处理程序仍然可以执行,例如......
spin_lock()不应该保护中断处理程序 - 只有用户上下文内核代码. spin_lock_irqsave()是中断禁用版本,这不是非抢占式单处理器上的无操作.
...或者我可能会调用一个能让原始线程进入睡眠状态的函数.
在持有旋转锁时不允许睡觉.这是"原子调度"错误.如果你想睡觉,你必须使用互斥量(再次 - 这些不是非抢占式单处理器上的无操作).
引自"Linux设备驱动程序",Jonathan Corbet,Alessandro Rubini和Greg Kroah-Hartman:
如果一个非抢占式单处理器系统进入锁定旋转,它将永远旋转; 没有其他线程能够获得CPU来释放锁(因为它无法产生).因此,在没有抢占的情况下,单处理器系统上的自旋锁操作被优化为什么都不做,除了改变IRQ屏蔽状态的那些(在Linux中,这将是
spin_lock_irqsave()).由于抢占,即使您从未期望您的代码在SMP系统上运行,您仍然需要实现正确的锁定.
如果您对在中断上下文(硬件或软件)中运行的代码可以使用的自旋锁感兴趣,则必须使用spin_lock_*禁用中断的形式.如果在您进入关键部分时中断到达,则不会这样做会使系统死锁.