死锁
死锁的基本概念
死锁:指多个进程在运行过程中因争夺资源而造成的一种僵局,当进程处于这种僵局状态时,若无外力作用,它们都将无法再向前推进
死锁产生的原因:
-
资源竞争(可剥夺资源和不可剥夺资源->死锁)
-
进程推进顺序不当
产生死锁的必要条件
资源分配图
资源分配图(Resource Allocation Graph)是描述死锁问题的常用工具,在很多问题的求解中都有应用。
死锁产生的必要条件
一旦死锁出现,这4个条件都必然成立。因此,只要有一个必要条件被系统或用户破坏掉,就不会出现死锁现象
特别注意:环路等待条件只是死锁产生的必要条件,而不是等价定义(充要条件)(死锁 => 四种必要条件 四种必要条件成立 ×=> 死锁 )
-
互斥条件(存在资源的互斥使用)
-
请求和保持条件(进程对其他资源进行申请,但是没有得到满足,但此时此进程所占有的资源也没有释放,于是申请和保持都存在)
-
不剥夺条件(进程在没有获得资源之前不能被其他进程切换掉)
-
环路等待条件(隐含着前三个条件,存在一种进程资源的循环等待链)
死锁一旦产生则死锁进程间必存在循环等待环,但存在循环等待环不一定产生死锁
死锁的处理
死锁的静态预防
破坏互斥条件
通过事先破坏死锁产生的四个必要条件中的一个或多个,从而预防死锁的发生。
但临界资源本身的性质决定对其的访问必须以互斥的方式,否则无法保证正确性。
不可行
破坏请求和保持条件
预分配资源方法:进程运行前,系统一次性地分配其运行所需的所有资源, 而不是随着进程的推进而陆续(动态)分配。预分配资源方法在实现上还有一个很大的缺陷,即系统无法在进程执行前精确估计其所需的全部资源。
另一种方法是:系统在进程执行前并不把其所需的所有资源分配给它, 而是边执行边申请资源,进程在申请新资源失败后,需要释放已 经占用的所有资源。
局限性:临界资源在没有使用完之前不能随意释放
破坏不可剥夺条件
这种方式仅仅对于那些状态容易保存和恢复的资源具有实际的意义
破坏环路等待条件
环路等待出现的根本原因是并发执行进程请求资源的顺序是随机的。一个进程先申请资源A再申请资源B, 另一个进程先申请资源B再申请资源A。
如果系统事先把全部资源按类型进行线性排队,并对每类资源赋予不同的序号,然后按序进行分配,规定进程已经申请了一类资源,则以后再申请资源,只能申请比之前申请到的资源序号高的资源。
不足:用户在编程时要牢记系统中所有资源的编号。
死锁的动态避免
死锁的避免对进程申请资源不做任何限制,允许进程动态(运行期间)地申请资源。
在死锁避免方式中,系统被定义为安全状态和不安全状态:
-
如果资源被假设分配给进程,系统处于安全状态,资源允许被分配给进程
-
如果资源被假设分配给进程,系统处于不安全状态,则申请被拒绝。
安全状态:所谓安全状态是指操作系统能够按照某种进程执行序列,如<P1,P2...Pn>,为进程分配所需资源,使得每个进程都能执行完毕,此时我们称系统处于安全状态
安全序列:进程执行<P1,P2...Pn>序列为当前系统的一个安全序列.
不安全状态:操作系统无法找到这样一个安全序列,则称当前系统处于不安全状态。
处于不安全状态的系统不一定形成死锁.因为进行的安全性检测是在部分进程之间进行的,其它的进程可能会释放资源,从而不会发生死锁
银行家算法
基本想法:在资源分配前,资源分配程序计算(假设)资源配后系统是否处于安全状态,如处于安全状态则把资源真正地分配给申请进程;
银行家算法的核心理念:是把资源分配给那些最容易执行完成的进程,保证系统中各个进程最终都能正常完成。
数据结构:
-
当前可分配的空闲资源向量Available(1:m)。m是系统中的资源类型数。Available[i]表示系统中现有的i类可用资源数量。
-
最大需求矩阵Max(1:n,1:m)。n是系统中的并发执行进程数。Max[i,j]表示进程i对j类资源的最大需求量。
-
资源分配矩阵Allocation(1:n,1:m)。Allocation[i,j]表示进程i已占有的j类资源的数量。
-
需求矩阵Need(1:n,1:m)。Need[i,j]表示进程i还需申请j类资源的数量。
Need[i,j] = Max[i,j] - Allocation[i,j]
算法过程:
进程Pi申请资源,用Request_i [j]来表示进程i向系统申请k个j类资源
-
如果Request_i [j] + Allocation[i,j] ≤ Max[i,j]成立,转向步骤2;如不成立,则说明进程的j类资源申请超过了其最大需求量,报错中断返回
-
如果Request_i [j] ≤ Available[i,j]成立,转向步骤3;如不成立,则说明系统中现有的j类资源不能满足进程Pi的资源申请。该请求不能满足,进程Pi被阻塞,结束算法返回。
-
系统试探着把资源分配给进程Pi,并修改下面数据结构中的值:
-
Available[j] -= Request_i[j];
-
Allocation[i] [j] += Request_i[j];
-
Need[i] [j] -= Request_i[j];
-
-
调用系统安全性检查算法,检查此次资源分配后系统是否处于安全状态。若安全,满足进程Pi的资源申请;否则,将本次试探分配作废,恢复原来资源分配状态,不响应进程Pi的资源申请, Pi阻塞等待
安全状态检查算法
数据结构:
-
工作向量Work[1:m]:它表示系统可提供给进程继续运行所需的各类资源数目,它含有m个元素, 表示系统中的资源类型数。Work = Available
-
布尔型向量Finish[1:n]:它表示系统是否有足够的资源分配给各个进程,使之运行完成。Finish[i] = false,当有足够的资源分配时Finish[i] = true;
过程:
-
初始化Work与Finish数组
-
从进程集合中寻找一个能满足下述条件的进程:Finish[i] = false && Need[i] [j] < Work[j];
-
当进程Pi获得资源后,可顺利执行,直 至完成,并释放资源,故应执行 Work[j] += Allocation[i] [j]; Finish[j] = true;
-
返回步骤二进行下一个安全状态序列的下一个进程
-
如果所有进程的Finish[i]=true 都满足,说明所有进程都已经出现在安全序列中,表明当前系统处于安全状态