Linux进程睡眠的原则

转自:http://blog.csdn.net/samantha_sun/article/details/6365770

为什么说在持有自旋锁时不能进入睡眠或阻塞


看LDD149页时,看到休眠的两条规则,其中之一是说,永远不要再原子上下文睡眠!


为什么说,驱动程序在持有自旋锁时绝对不能进入睡眠,而在拥有信号量时就可以?

 

 

看到网上有人这么提问,这也是我读书时候自己迷惑不解的地方。但是,通过仔细研读,我理解到了这个问题的答案。我在网上也看了大家对于这个问题的回答,大都没说到点上。根据我自己的理解,应该是:

 

 

自旋锁自旋锁禁止处理器抢占;而信号量不禁止处理器抢占。

 

基于这个原因,如果自旋锁在锁住以后进入睡眠,由于不能进行处理器抢占,其他系统进程将都不能获得CPU而运行,因此不能唤醒睡眠的自旋锁,因此系统将不响应任何操作(除了中断或多核的情况,下面会讨论)。而信号量在临界区睡眠后,其他进程可以用抢占的方式继续运行,从而可以实现内存拷贝等功能而使得睡眠的信号量程序由于获得了等待的资源而被唤醒,从而恢复了正常的代码运行。

 

当然,自旋锁的睡眠的情况包含考虑多核CPU和中断的因素。自旋锁睡眠时,只是当前CPU的睡眠以及当前CPU的禁止处理器抢占,所以,如果存在多个CPU,那么其他活动的CPU可以继续运行使操作系统功能正常,并有可能完成相应工作而唤醒睡眠了的自旋锁,从而没有造成系统死机;自旋锁睡眠时,如果允许中断处理,那么中断的代码是可以正常运行的,但是中断通常不会唤醒睡眠的自旋锁,因此系统仍然运行不正常。

 

以上是我对这个问题的理解。如果有说错的地方,非常希望高手给予指正!谢谢。

其实这个问题可以自己写个小程序测试一下,我现在也正在读书,还没有测试,其实测试很简单,写一个自旋锁,然后睡眠,看看在单CPU下系统是不是死机了,就可以清楚。估计死机时还应该可以响应键盘操作,因为键盘是中断处理,测试时把中断屏蔽了,也是一个不错的办法。




在单核cpu上,只需要关闭中断就可以保证原子操作。。。。。原子操作完成后打开中断即可。

但是在多核cpu上,关闭中断不能保证其他的cpu不进行资源的操作,但是多个cpu共享一条总线,所以只要锁住总线便能保证原子操作。自旋锁的原理便是如此。

自旋锁可分为用在单核处理器上和用在多核处理器上。

单核处理器:
用在单核处理器上,又可分为两种:
1.系统不支持内核抢占
此时自旋锁什么也不做,确实也不需要做什么,因为单核处理器只有一个线程在执行,又不支持内核抢占,因此资源不可能会被其他的线程访问到。
2.系统支持内核抢占
这种情况下,自旋锁加锁仅仅是禁止了内核抢占,解锁则是启用了内核抢占。
在上述两种情况下,在获取自旋锁后可能会发生中断,若中断处理程序去访问自旋锁所保护的资源,则会发生死锁。因此,linux内核又提供了spin_lock_irq()和spin_lock_irqsave(),这两个函数会在获取自旋锁的同时(同时禁止内核抢占),禁止本地外部可屏蔽中断,从而保证自旋锁的原子操作。

多核处理器:
多核处理器意味着有多个线程可以同时在不同的处理器上并行执行。举个例子:
四核处理器,若A处理器上的线程1获取了锁,B、C两个处理器恰好这个时候也要访问这个锁保护的资源,因此他俩CPU就一直自旋忙等待。D并不需要这个资源,因此它可以正常处理其他事情。 关闭中断不能保证其他的cpu 不进行资源的操作,但是多个cpu 共享一条总线,所以只要锁住总线便能保证原子操作。自旋锁的原理便是如此。

自旋锁的几个特点:
1.被自旋锁保护的临界区代码执行时不能睡眠。单核处理器下,获取到锁的线程睡眠,若恰好此时CPU调度的另一个执行线程也需要获取这个锁,则会造成死锁;多核处理器下,若想获取锁的线程在同一个处理器下,同样会造成死锁,若位于另外的处理器,则会长时间占用CPU等待睡眠的线程释放锁,从而浪费CPU资源。
2.被自旋锁保护的临界区代码执行时不能被其他中断打断。原因同上类似。
3.被自旋锁保护的临界区代码在执行时,内核不能被抢占,亦同上类似。

 




多线程和多处理器的关系:

1.       单核cpu DPC/Dispatch级别的中断导致线程切换

2.       多核cpu 

1)某个cpu的中断导致线程的切换

2)多个cpu可以同时使得多个线程运行

 

 

在单核cpu上,只需要关闭中断就可以保证原子操作。。。。。原子操作完成后打开中断即可。

但是在多核cpu上,关闭中断不能保证其他的cpu不进行资源的操作,但是多个cpu共享一条总线,所以只要锁住总线便能保证原子操作。自旋锁的原理便是如此。

 

 

自旋锁和其他的同步对象event的区别:

 

线程使用其他的同步对象进行同步操作时,如果遇到等待,那么内核便会切换任务,让cpu运行其他的线程。。。。。。但是这个切换包括(原有线程上下文的保存,调度算法的执行,cache失效,cr3的修改。。。)如果同步操作仅仅有两条指令,那么这个代价是非常昂贵的,还不如让等待线程空转自旋。不断测试自旋锁的状态。。。

 

 

Q1:如何保证对自旋锁的状态操作是原子的?

A1:这个只能通过硬件来实现。因为多个cpu共享同一条总线,所以锁住总线便能保证对自旋锁的操作时原子的。

 

 

Q2:获得自旋锁时,为什么要提升中断请求级别(IRQL)DISPATCH_LEVEL

 

提升到Dispatch级别时为了能够禁止软中断,保证持有该锁的线程能够尽快使用完,然后释放。因为其他的cpu在空转。尽少的减少cpu资源的浪费。

 

多线程和多处理器的关系:

1.       单核cpu DPC/Dispatch级别的中断导致线程切换

2.       多核cpu 

1)某个cpu的中断导致线程的切换

2)多个cpu可以同时使得多个线程运行

 

 

在单核cpu上,只需要关闭中断就可以保证原子操作。。。。。原子操作完成后打开中断即可。

但是在多核cpu上,关闭中断不能保证其他的cpu不进行资源的操作,但是多个cpu共享一条总线,所以只要锁住总线便能保证原子操作。自旋锁的原理便是如此。

 

 

自旋锁和其他的同步对象event的区别:

 

线程使用其他的同步对象进行同步操作时,如果遇到等待,那么内核便会切换任务,让cpu运行其他的线程。。。。。。但是这个切换包括(原有线程上下文的保存,调度算法的执行,cache失效,cr3的修改。。。)如果同步操作仅仅有两条指令,那么这个代价是非常昂贵的,还不如让等待线程空转自旋。不断测试自旋锁的状态。。。

 

 

Q1:如何保证对自旋锁的状态操作是原子的?

A1:这个只能通过硬件来实现。因为多个cpu共享同一条总线,所以锁住总线便能保证对自旋锁的操作时原子的。

 

 

Q2:获得自旋锁时,为什么要提升中断请求级别(IRQL)DISPATCH_LEVEL

 

提升到Dispatch级别时为了能够禁止软中断,保证持有该锁的线程能够尽快使用完,然后释放。因为其他的cpu在空转。尽少的减少cpu资源的浪费。

 

多线程和多处理器的关系:

1.       单核cpu DPC/Dispatch级别的中断导致线程切换

2.       多核cpu 

1)某个cpu的中断导致线程的切换

2)多个cpu可以同时使得多个线程运行

 

 

在单核cpu上,只需要关闭中断就可以保证原子操作。。。。。原子操作完成后打开中断即可。

但是在多核cpu上,关闭中断不能保证其他的cpu不进行资源的操作,但是多个cpu共享一条总线,所以只要锁住总线便能保证原子操作。自旋锁的原理便是如此。

 

 

自旋锁和其他的同步对象event的区别:

 

线程使用其他的同步对象进行同步操作时,如果遇到等待,那么内核便会切换任务,让cpu运行其他的线程。。。。。。但是这个切换包括(原有线程上下文的保存,调度算法的执行,cache失效,cr3的修改。。。)如果同步操作仅仅有两条指令,那么这个代价是非常昂贵的,还不如让等待线程空转自旋。不断测试自旋锁的状态。。。

 

 

Q1:如何保证对自旋锁的状态操作是原子的?

A1:这个只能通过硬件来实现。因为多个cpu共享同一条总线,所以锁住总线便能保证对自旋锁的操作时原子的。

 

 

Q2:获得自旋锁时,为什么要提升中断请求级别(IRQL)DISPATCH_LEVEL

 

提升到Dispatch级别时为了能够禁止软中断,保证持有该锁的线程能够尽快使用完,然后释放。因为其他的cpu在空转。尽少的减少cpu资源的浪费。

 


3楼 huofen20052012-03-27 09:13发表 [回复]
所有的原则,都是为了保证单cpu上任务操作的原子性。
而睡眠,则内部破坏了这个原子性,系统没法阻止,只能报错提醒。
--
多cpu的时候,A核上拿到锁的时候,其他核会自旋等待(某硬件同步机制来保证)。
2楼 huofen20052012-03-27 09:09发表 [回复]
这个理解是不对的:
--
在单CPU系统里面,自旋锁被简化为关抢占,关中断,其余什么都不干(这时候,自旋锁的本质在于抓住cpu不放,而不是自旋等待资源了)!
--
A任务拿住自旋锁,然后进行睡眠/阻塞 -> 激发调度,然后B任务就拿到异常状态(A尚未释放)的自旋锁了! //锁失效!
这个时候,系统会报类似错误:
BUG: scheduling while atomic: processB/1750/0x00000100
1楼 Young_Xu2011-06-29 21:08发表 [回复]
I agree with you![e01]
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值