进程管理之死锁

前面两篇博客

1.进程同步之临界区域问题及Peterson算法

2.进程同步之信号量机制(pv操作)及三个经典同步问题

介绍了进程管理中进程同步的诸多问题,下面为大家详细解读进程管理中死锁的问题及其解决方案。


1.什么是死锁?

在多道程序设计环境下,多个进程可能竞争一定数量的资源。一个进程申请资源,如果资源不可用,那么进入等待状态。如果所申请的资源被其他等待进程占有,那么该等待进程有可能无法改变状态,这种情况称为死锁(deadlock)

设系统有一台打印机(R1),一台读卡机(R2),两进程共享这两台设备。
        用信号量S1表示R1是否可用,初值为1;
        用信号量S2表示R2是否可用,初值为1;
                             
这两个进程在并发执行过程中,可能会发生如下的情况。

即P1占用R1,P2占用R2,同时P1和P2又分别申请R2和R1的资源。于是造成了死锁。

大家可以思考一下,如何修改A、B进程才不会发生死锁。带着这个问题我们往下看。


2.产生死锁的原因

  • 竞争系统资源
如循环图所示:
系统中只有一台打印机R1和一台读卡机R2,可供进程P1和P2共享。R1、R2已经分别分配给P1、P2使用,当P1、P2在不释放资源R1、R2而又同时分别申请R2、R1(如图),形成环路,这样会产生死锁。

  • 进程的推进不当
如前面的例子可知他只是可能发生死锁,也就是说进程的推进不同会导致不同的结果。

3.产生死锁的必要条件

互斥条件

进程要求对所分配的资源进行排它性控制,即在一段时间内某资源仅为一进程所占用。

占有并等待条件

当进程因请求资源而阻塞时,对已获得的资源保持不放。

非抢占条件

进程已获得的资源在未使用完之前,不能剥夺,只能在使用完时由自己释放。

循环等待条件

在发生死锁时,必然存在一个进程--资源的环形链。


4.解决死锁的基本方法

1.预防死锁

前面我们降到了死锁的必要条件,那么只要一个条件不满足的话,就不会发生死锁了。所以我们可以从必要条件的角度来预防死锁。
a.互斥条件
对于非共享资源,必须有互斥条件。而共享资源是不会涉及死锁。所以通常不能通过否定互斥条件来预防死锁:有些资源本身是非共享的。
b.占有并等待
为了确保该条件不在系统内出现,必须保证:当一个进程申请一个资源时,它不能占有其他资源。
资源一次性分配 可以解决这个问题。实现这一分配有两种协议
1.每个进程在执行前申请并获得所有资源。
2.允许进程在没有资源时才可申请资源。

两种协议的缺点:
1.资源利用率不高
2.可能发生饥饿(磁带用到一般被抢了)
c.非抢占
允许当前进程被其他进程抢过去。
缺点:可能发生饥饿(磁带用到一般被抢了)
d.循环等待条件
确保此条件不成立的方法就是对所有资源类型进行完全排序,且要求每个进程按递增顺序来申请资源。
实现方法:资源有序分配法
遵循两种协议:
1.每个进程只按递增顺序申请资源。(第一次可以申请多个,但之后申请编号必须比前面大)
2.进程申请编号比拥有资源编号小时必须先释放大编号资源。
             

这样进程如果需要磁带机和绘图机,那进程必须先申请磁带机,再申请绘图机。如果再想申请打印机,则必须先释放绘图机。

2.避免死锁

通过前面介绍想必大家也看到了在预防死锁的过程中会严重系统性能。因此在避免死锁中我们不得不施加较弱的限制,从而获得比较满意的性能。

由于在避免死锁的策略中,允许进程动态地申请资源。因而,系统在进行资源分配之前预先计算 资源分配的安全性。若此次分配不会导致系统进入不安全状态,则将资源分配给进程;否则,进程等待。
最具代表性的避免死锁的算法是银行家算法。由于银行家算法比较复杂,我将在下篇博客中详细解读。




一般来说,由于操作系统有并发,共享以及随机性等特点,通过预防和避免的手段达到排除死锁的目的是很困难的。这需要较大的系统开销,而且不能充分利用资源。
为此,一种简便的方法是系统为进程分配资源时,不采取任何限制性措施,但是提供了检测和解脱死锁的手段:能发现死锁并从死锁状态中恢复出来。
因此,在实际的操作系统中往往采用死锁的检测与恢复方法来排除死锁。 死锁检测与恢复是指系统设有专门的机构,当死锁发生时,该机构能够检测到死锁发生的位置和原因,并能通过外力破坏死锁发生的必要条件,从而使得并发进程从死锁状态中恢复出来。

1.一个用来检查系统状态从而确定是否出现了死锁算法。即死锁检测
2.一个用来从死锁状态中恢复的算法。即恢复算法

3.死锁检测

首先可以通过画分配图来判断是否发生了死锁。但如何用算法来判断呢?

死锁检测算法。算法使用的数据结构是如下这些:      

       占有矩阵A:n*m阶,其中n表示并发进程的个数,m表示系统的各类资源的个数,这个矩阵记录了每一个进程当前占有各个资源类中资源的个数。
       申请矩阵R:n*m阶,其中n表示并发进程的个数,m表示系统的各类资源的个数,这个矩阵记录了每一个进程当前要完成工作需要申请的各个资源类中资源的个数。
       空闲向量T:记录当前m个资源类中空闲资源的个数。
       完成向量F:布尔型向量值为真(true)或假(false),记录当前n个并发进程能否进行完。为真即能进行完,为假则不能进行完。
       临时向量W:开始时W:=T。

算法步骤:
     (1)W:=T,
     对于所有的i=1,2,...,n,
     如果A[i]=0,则F[i]:=true;否则,F[i]:=false
     (2)找满足下面条件的下标i:
     F[i]:=false并且R[i]〈=W
     如果不存在满足上面的条件i,则转到步骤(4)。
     (3)W:=W+A[i]
     F[i]:=true
     转到步骤(2)
     (4)如果存在i,F[i]:=false,则系统处于死锁状态,且Pi进程参与了死锁。什麽时候进行死锁的检测取决于死锁发生的频率。如果死锁发生的频率高,那麽死锁检测的频率也要相应提高,这样一方面可以提高系统资源的利用率,一方面可以避免更多的进程卷入死锁。如果进程申请资源不能满足就立刻进行检测,那麽每当死锁形成时即能被发现,这和死锁避免的算法相近,只是系统的开销较大。为了减小死锁检测带来的系统开销,一般采取每隔一段时间进行一次死锁检测,或者在CPU的利用率降低到某一数值时,进行死锁的检测。 


4.死锁的恢复  

  一旦在死锁检测时发现了死锁,就要消除死锁,使系统从死锁状态中恢复过来。  

    (1)最简单,最常用的方法就是进行系统的重新启动,不过这种方法代价很大,它意味着在这之前所有的进程已经完成的计算工作都将付之东流,包括参与死锁的那些进程,以及未参与死锁的进程。

    (2)撤消进程,剥夺资源。终止参与死锁的进程,收回它们占有的资源,从而解除死锁。这时又分两种情况:一次性撤消参与死锁的全部进程,剥夺全部资源;或者逐步撤消参与死锁的进程,逐步收回死锁进程占有的资源。一般来说,选择逐步撤消的进程时要按照一定的原则进行,目的是撤消那些代价最小的进程,比如按进程的优先级确定进程的代价;考虑进程运行时的代价和与此进程相关的外部作业的代价等因素。 

  此外,还有进程回退策略,即让参与死锁的进程回退到没有发生死锁前某一点处,并由此点处继续执行,以求再次执行时不再发生死锁。虽然这是个较理想的办法,但是操作起来系统开销极大,要有堆栈这样的机构记录进程的每一步变化,以便今后的回退,有时这是无法做到的。



转载请注明出处:http://blog.csdn.net/speedme


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值