死锁的定义
如果一组进程中的每一个进程都在等待仅由改组进程中的其它进程才能引发的时间,那么该组进程就是死锁的。
死锁的产生几种情况
- 竞争不可抢占性资源引发死锁
- 竞争可消耗资源引发死锁
- 进程推进顺序不当引发死锁
产生死锁的四个必要条件
- 互斥条件
- 请求和保持条件
- 不可抢占条件
- 循环等待条件
互斥条件
互斥条件也就是进程之间的互斥性,当一个进程访问某种资源时,该资源只能被一个进程占用,即其他进程要使用该资源就只能等待。
请求和保持条件
当一个进程已经占有了一个资源的时候,它又请求占用另外一个资源,而请求资源已经被另外一个进程占用,此时请求进程被阻塞,但自己所获得资源保持不放
不可抢占条件
进程已获得的资源在未使用完全之前不可被抢占,只能在自己使用结束之后自己释放
循环等待条件
即为环路等待,在发生死锁是,必然存在一个进程–资源的循环链,即多个进程互相等待其所占的资源而形成一个环状结构
预防死锁的方法
预防死锁要从死锁的四个必要条件入手,破坏其中的任意一个就能达到预防死锁的目的。但由于互斥条件是非共享设备所必需的,不仅不能改变,还应该加以办证,因此就只能破坏死锁的后三个条件。
破坏“请求和保持”条件
需要破坏该条件,系统就必须要保证做到:当一个进程在请求资源的时候,它不能持有不可抢占资源。因此有以下两个协议来实现:
第一种协议
规定所有进程在开始运行之前,必须一次性的申请其在整个运行过程所需要的所有资源,只要有一种资源不足,那么所有资源都不能非配给进程,这样就保证了一个进程不会持有不可抢占资源。
该协议的优点就是简单、易行且安全,但是他也有些严重的缺点。
- 严重的浪费了资源,严重的恶化了资源的利用率
- 会使进程经常产生饥饿现象
第二种协议
这是对第一种协议的改进。允许一个进程只获得运行初期的所需资源后,便开始运行,其后再逐步释放已经非配给自己的、且使用完毕的全部资源,然后再请求新的资源。这样的话就会很好提高资源的利用率,还减少了进程发生饥饿的几率。
破话“不可抢占”条件
协议规定当一个已经保持了某种不可抢占资源的进程,提出新的资源请求而不能得到满足时,它必须释放已经保持的所有资源,待到以后需要的时候再重新申请。
这种方法的实现比较复杂,且会付出很大的代价,并且会延长进程的周转时间,而且也增加了系统的开销,降低了系统吞吐量。
破坏“循环等待”条件
规定当系统对所有资源进行线性排序后,每个进程必须按序号递增的顺序请求资源。
这种方法虽然在资源利用率和系统吞吐量上都有显著的改善,但是也存在以下问题:
- 为系统中各类资源所规定的序号必须相对稳定,这就限制了新设备的增加
- 会经常发生作业使用各类资源顺序与系统规定的顺序不同,从而造成资源浪费
- 限制了用户简单、自主编程
避免死锁
除预防死锁外,我们还能通过避免死锁来实现预防死锁的发生。
系统安全状态
系统的状态分为安全状态和不安全状态,当系统处于安全状态的时候,可避免死锁,当系统处于不安全状态的时候,就可能进入死锁状态,因此,这个方法的最主要的目标就是使系统一直处于安全状态,这样就能很好的避免死锁。而如何保证其处于安全状态,也就是每次分配资源的时候,都要保证系统会处于安全状态下才进行分配。
银行家算法避免死锁
这是最有代表性的避免死锁的方法,之所以叫做银行家算法,是因为该算法原本是为银行系统而设计的。
算法的前提:每一个新进程在进入系统的时候,必须申明在运行过程,可能需要每种资源的类型的最大单元数目,其数目不能超过系统所拥有的资源总量。然后当进程请求一组资源的时候,系统必须先要确定是否有足够的资源分配给该进程,若有,就进一步计算分配该进程是否会使系统处于不安全状态,如果不会,才分配给它,否则,进程等待。
首先需要了解下银行家算法中的数据结构:
- 可利用资源资源向量Available.
- 最大需求矩阵Max
- 分配矩阵Allocation
- 需求矩阵Need
算法实现:
设Request_i是进程P_i的请求向量,若果Request_i[j] = K,表示进程P_i需要K个R_j类型的资源,当P_i发出资源请求时,系统按以下步骤检查:
1.如果Requst_i[j] <= Need[i, j],便转向步骤2,否则认为出错。
2. 如果Requst_i[j] <= Available[j],便转向步骤3,否则表示尚无足够的资源,P_i进程等待
3. 系统试探着把资源分配给进程P_i,并修改下面数据结构中的数值:
Available[j] = Available[j] - Request_i[j];
Allocation[i,j] = Allocation[i,j] + Request_i[j];
Need[i,j] = Need[i,j] - Request_i[j];
4.系统安全性算法,检查此次资源分配后系统是否处于安全状态,只有处于安全状态的时候才会把资源分配P_i;
安全性算法的实现
1.设置两个变量:工作向量Work,它含有m个元素,开始时,Work := Avaliable和Finsh,开始时先使Finish[i] := false,当有足够的资源分配给进程时,再令Finsh[i] :=true;
2.查找一个满足下列条件的进程:
Finsh[i] = false;
Need[i,j] <= Work[j];
找到了执行3,否则执行4
3.当进程P_i获得资源后,可顺利执行,直至完成,并释放出分配给它的资源,因此执行:
Work[j] = Work[j] + Allocation[i,j]
Finish[i] = true;
go to step 2;
4.如果所有进程的Finish[i] = true都满足,则表示系统处于安全状态,否则就处于不安全状态。