2010-07-30 50 views
4

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

我无法理解:它不应该等同于互斥体上的睡眠吗?即使在非预编译的内核中,中断处理程序仍然可能会被执行,或者我可能会调用一个函数来使原始线程进入休眠状态。所以,如果一个空的spin_lock调用是作为互斥体实现的,那么它就是“安全”的,这是不正确的。

有什么我不明白吗?

回答

5

«Linux设备驱动程序»,由乔纳森·科比特,亚历山德罗Rubini和葛雷格·克罗哈曼报价:

如果一个非抢占的单处理器系统曾经走进一个 锁旋转,它会旋转永远;没有其他线程能够获得CPU释放锁(因为它不能屈服)。 正因为如此,在未启用 抢占单处理器系统上自旋锁操作进行了优化,什么也不做,用的 不同之处在于改变IRQ屏蔽状态的那些(在Linux中,这将是 spin_lock_irqsave())。由于抢占,即使您从未使用 希望您的代码在SMP系统上运行,您仍需要实施 正确的锁定。

如果您对可以在中断环境(硬件或软件)中运行的代码执行的自旋锁感兴趣,则必须使用禁用中断的形式spin_lock_*。如果不这样做,只要进入临界区时中断到达,就会使系统死锁。

+0

事实上,由于spin_lock调用禁用抢占,所以先发制人的单处理器系统的情况是相同的。 – Dipstick 2011-07-02 08:11:28

+0

-1复制/粘贴没有署名。在引用时,请说清楚并至少提供原作者的姓名! http://books.google.ch/books?id=M7RHMACEkg4C&pg=PT137&lpg=PT137&dq=%22If+a+nonpreemptive+uniprocessor+system+ever+went+into+a+spin+on+a+lock%22&source=bl&ots = s1I5OjeNVv&SIG = VklYdozQ9pAkuzxUAdvlPjcFHe8&HL = EN&SA = X&EI = s_7tUJ_UJ6qN4gS68oHACg&VED = 0CFoQ6AEwBw – Macmade 2013-01-09 23:38:01

1

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

+1

此外,这是否意味着我不能在我的螺旋锁临界区进行可能阻塞的调用? (如kmalloc或printk?) – Emiliano 2010-07-30 14:56:32

+0

除非所有其他用户在自锁之前禁用IRQ(请参见Erics答案),否则不应使用自旋锁。如果允许的话,您描述的情况会导致死锁(处理器在IRQ处理程序中旋转,但如果没有处理器运行其他代码,锁定永远不会释放)。 – 2010-07-30 18:59:23

+0

@happy_emi要回答你的另一个问题,在拿着螺旋锁的同时,你不应该打电话,可能会阻止,睡眠或重新安排,因为这也可能导致死锁。 – 2010-07-30 21:54:22

6

如果您在非抢先式内核上使用spin_lock()来屏蔽数据与中断处理程序之间的关系,则会导致死锁(在单处理器计算机上)。

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

只有锁定座始终能够完成时才能使用自旋锁。

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

6

要回答你的问题的两个部分:

即使在非preemtive内核中断处理程序可能仍然例如执行...

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

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

在持有自旋锁时不允许睡觉。这是“Scheduling while atomic”错误。如果你想睡觉,你必须使用互斥锁(再次 - 这些不是非抢先式单处理器上的禁止操作)。