我们先看一个生活中一个死锁的例子
其实我们的生活中经常会有各种各样的死锁现象发生,同样在操作系统编程上也存在着各种各样的一不小心就会陷入死锁问题!
死锁概念
死锁是指多个进程(线程)因竞争资源而造成的一种僵局。当等待的资源一直得不到释放,死锁会一直持续下去。死锁一旦发生,程序本身是解决不了的,只能依靠外部力量使得程序恢复运行,例如重启,开门狗复位等。
死锁产生的原因
(1)系统资源的竞争
通常系统中拥有的不可剥夺资源,其数量不满度多个进程运行的需要,造成进程在运行时,会因为争夺资源而陷入僵局(类似于马路上两个陌生人同时看到100元钱,两个人同时去捡,谁都不肯放手,两个人就一直在那里一人扯着一半僵持着自行脑补画面)。只有对不可剥夺的资源进行争夺才可能发生死锁,对可剥夺的资源的竞争不会发生死锁。
(2)进程推进顺序非法
进程在运行过程中,请求和释放资源的顺序不当,也同样会导致死锁。例如并发进程P1、P2分别占有了资源R1、R2,而进程P1申请资源R2、进程P2申请资源R1时,两者都会因为所需要的资源被占用而阻塞(典型例子有ABBA锁(简化的哲学家进餐问题),自死锁(自己有一个未释放的锁,然后又去临界区申请该锁)等。
信号量使用不当也会造成死锁。进程间彼此相互等待对方发来的消息,也会使得这些进程无法继续向前推进。例如,进程A等待进程B发的消息,进程B又在等待进程A发的消息,此时A、B不是因为竞争资源,而是在等待对方的资源导致死锁(有点像TCP的三次握手四次挥手:我怎么知道我发的信号你到底收到没)。
(3)死锁产生的必要条件
死锁产生必须同时满足以下四个条件,只要其中一个不成立,那么就不会产生死锁!
- 互斥条件:在一个时间段内某资源只能被一个进程占有。
- 不剥夺条件:进程获得资源在未使用完成之前,不可以被其他进程强行夺走,资源只能是主动释放。
- 请求并保持条件:进程已经拥有了至少一个的资源,但是又提出了新的资源请求,而这个资源又被其他进程占有,此时请求被阻塞,同时自己已经占有的资源不进行释放。
- 循环等待条件:每个进程都请求下一个进程所拥有的资源,而构成一个资源循环等待环。
注:循环等待不是产生死锁的充要条件,只是必要条件,只有等待环中的请求资源唯一时才是充要条件。
请求资源唯一,死锁产生充要条件
满足进程p4请求的资源数目大于1,并且该资源不在请求环中,所以该请求链虽然含有环,但是不一定产生死锁
死锁处理策略
(1)死锁的预防
防止死锁的发生只需要破坏产生死锁的四个必要条件当中的一个就能预防死锁。
(2)死锁的避免
在资源的动态分配过程中,用某种方法找到进程安全序列防止系统进入不安全的状态,从而避免死锁。银行家算法最著名是死锁避免算法。
(3)死锁的检测和解除
在资源分配当中不采取任何限制性措施,允许进程在运行中发生死锁,然后利用系统检测机构及时地检测出死锁的发生,然后采取以下措施解决死锁。
- 资源剥夺法:挂起某些死锁进程,并抢占它的资源,将这些资源分配给其他的锁死进程。(注:但是要防止挂起的进程长时间得不到资源而饥饿,甚至饿死(即使得到了资源完成任务也不在具有意义))
- 撤销进程法:强制撤销部分、甚至全部死锁进程并剥夺这些进程的资源。撤销原则可以按进程优先级和进程撤销的代价的高低决定。
- 进程回退法:让一个或多个进程回退到足以满足不产生死锁的的地步,进程回退时自愿释放资源而不是剥夺资源。要求系统要保持进程的历史信息,设置还原点。
ps: 对于死锁的检测:Linux系统在2006年引入死锁检测模块Lockdep。对于死锁的解除:当系统发生死锁时不会对用户造成多大影响,或系统很少发生死锁的场合采用允许死锁发生的鸵鸟算法。大多数操作系统,包括UNIX,LINUX和Windows处理死锁问题的办法仅仅是忽略它。其假设前提是大多数用户宁可在极偶然的情况下发生死锁也不愿接受因为死锁解决算法带来的性能上的损失。因为解决死锁的问题,通常代价很大。
如有错误望不吝指教!
欢迎转载,转载请注明出处!