避免死锁的本质在于,系统在进行资源分配的时候,应使系统不进入不安全状态
举个简单的例子,假如银行贷款,这里总共可以有12万可以贷出去,三个人A要求分期贷款总共10万,B要求分期贷款4万,C要求分期贷款9万,乍一看银行的钱肯定不够这三人贷的,但是聪明的银行家就想出了一个好办法(前提是每个人都按时还贷款) 首先先贷款给A--5万,B--2万元, C--2万元 此时银行里面还有3万元,在这个时候只要在第二次放贷的时候,假设B能够提前把那2万块钱还回来就能保证正常贷款给A,以此类推C也能够在某段时期内得到银行的二次放贷,这种情况下银行不会担心资金链会断裂的问题(即进入不安全状态)
但是如果不按照安全的序列去分配这12万,则银行可能就会出现资金链断裂的问题,举例:假如在上述状态下C贷3万后又多贷了1万块,则此时银行就会出现资金断裂,让我们来分析下,此时剩余可以贷款是2万块,假如把剩余2万贷给B(这时B贷到了他所想要的),但是当B用完还回来的时候是4万块,而这4+5=9万不能满足A的贷款要求10万,也不能满足C的贷款9万的要求4+3=7 ,类似的如果把剩余的2万先贷给A或者C也都不行,致使这种情况下,A在等待资源 C也在等待资源,但是银行却放不出来贷款的情况,此时银行可以关门大吉了(即所谓的死锁),所以从C多贷的1万块钱开始,银行的资金链就不充足了(即我们所说的系统此时进入了不安全状态,进入不安全状态并不是说一定会死锁,是有可能进入死锁状态),在上述额例子中,尽管银行还有库存,但是却不能贷出去。
下面来说下银行家算法中的数据结构,在系统中必须设置这样四个数据结构,分别用来描述系统中1.可利用的资源(即上面例子中还剩下3万元可以贷),2.所有进程对资源的最大需求(这个就是ABC要求贷款的数量)3,系统中的资源分配(即上面所说的首先贷5万2万2万)4 以及进程还需要多少资源(这个不难理解)
1可利用资源用Avaliable表示,这是一个含有m个元素的数组,其中的每一个元素代表一类可利用的资源数目,其初始值是系统中所分配的该类的全部可用资源的数目,其数值随着该类资源的分配和回收而动态的改变,如果Avaliable[j]=K表示系统中现有Rj类资源K个
2最大需求矩阵Max。这个是n*m的矩阵,定义了系统中n个进程的每一个进程对m类资源的最大需求,如果Max[i,j]=K表示进程i需要Rj类资源的最大数目为K
3分配矩阵Allocation,这也是一个n*m的矩阵,它定义了系统中的每一类资源当前已经分配给每一个进程的资源数,如果Allocation[i,j]=K表示进程i当前已经分的Rj类资源的数目为K
4需求矩阵Need,这也是一个n*m的矩阵,用以表示每一个进程尚需的各类资源数,如果Need[i,j]=K,则表示进程i还需要RJ类资源K个方能完成任务
上述三个矩阵之间的关系:Need[i,j]=Max[i,j]-Allocation[i,j]
下面是银行家算法:设Request是进程Pi的请求量,如果Requesti[j]=K表示进程Pi需要K个Rj类型的资源,当Pi发出请求以后系统按照以下步骤进行检查:
1如果Requesti[j]<=Need[i,j]便转向2否则认为出错,因为它所需的资源数已经超过它宣布的最大值
2如果Requesti[j]<=Avaliable[j]便转向3 否则表示尚无足够资源, Pi必须等待
3系统试探着把资源分配给进程Pi,并修改下面数据结构的值:
Avaliable[j]=Avaliable[j]-Requesti[j];
Allocation[i,j]=Allocation[i,j]+Requesti[j];
Need[i,j]=Need[i,j]-Requesti[j];
4系统执行安全性算法,检查此次资源分配后系统是否处于安全状态,若安全,则才正式将资源分配给进程Pi,以完成本次分配,否则回复原来的资源分配状态
下面看下有关资源分配图的概念一下是截取别人的东西
二 化简资源分配图
方法步骤
- 第一步:先看系统还剩下多少资源没分配,再看有哪些进程是不阻塞(“不阻塞”即:系统有足够的空闲资源分配给它)的
- 第二步:把不阻塞的进程的所有边都去掉,形成一个孤立的点,再把系统分配给这个进程的资源回收回来
- 第三步:看剩下的进程有哪些是不阻塞的,然后又把它们逐个变成孤立的点。
- 第四步:最后,所有的资源和进程都变成孤立的点。这样的图就叫做“可完全简化”。
如果一个图可完全简化,则不会产生死锁;如果一个图不可完全简化(即:图中还有“边”存在),则会产生死锁。这就是“死锁定理”。
实例
- 第一步:先看R1资源,它有三个箭头是向外的,因此它一共给进程分配了3个资源,此时,R1没有空闲的资源剩余。
- 第二步:再看R2资源,它有一个箭头是向外的,因此它一共给进程分配了1个资源,此时,R2还剩余一个空闲的资源没分配。
- 第三步:看完资源,再来看进程,先看进程P2,它只申请一个R1资源,但此时R1资源已经用光了,所以,进程P2进入阻塞状态,因此,进程P2暂时不能化成孤立的点。
- 第四步:再看进程P1,它只申请一个R2资源,此时,系统还剩余一个R2资源没分配,因此,可以满足P1的申请。这样,进程P1便得到了它的全部所需资源,所以它不会进入阻塞状态,可以一直运行,等它运行完后,我们再把它的所有的资源释放。相当于:可以把P1的所有的边去掉,变成一个孤立的点,如下图所示:
- 第五步:进程P1运行完后,释放其所占有的资源(2个R1资源和1个R2资源),系统回收这些资源后,空闲的资源便变成2个R1资源和1个R2资源,由于进程P2一直在申请一个R1资源,所以此时,系统能满足它的申请。这样,进程P2便得到了它的全部所需资源,所以它不会进入阻塞状态,可以一直运行,等它运行完后,我们再把它的所有的资源释放。相当于:可以把P2的所有的边都去掉,化成一个孤立的点,变成下图:
由于这个资源分配图可完全简化,因此,不会产生死锁。
而如果资源分配图中的点,最终不能够化成孤立的点,则进程资源图不能够完全简化,从而会发生死锁