mapengpeng1999@163.com 操作系统5~死锁

死 锁

1.死锁的概念和产生原因

1.1 死锁的基本概念

1.死锁:指一组并发执行的进程,彼此等待对方释放资源。而在未得到对方所占资源之前,各进程都不释放自己占有的资源,从而导致该组进程都不能向前推进。
2.死锁产生后,在无外力干预下,陷入死锁的各进程都永远不能向前推进,导致这些进程不能正常结束。同时,要求共享使用死锁进程所占资源的其他进程、或需要与死锁进行某种合作的其他进程,也会受到牵连而不能正常结束,最终可能导致系统瘫痪。

在这里插入图片描述

在这里插入图片描述

​ 通过例子可发现,死锁具有以下特点:
​ ① 陷入死锁的进程是系统并发进程中的一部分,且至少要有2个进程,单个进程不能形成死锁。
​ ② 陷入死锁的进程,彼此都在等待对方释放资源,形成一个循环等待链。
​ ③ 死锁形成后,在没有外力干预下,陷入死锁的进程不能自己解除死锁,死锁进程无法正常结束。
​ ④ 如不及时解除死锁,死锁进程占有的资源不能被其他进程所使用,导致系统中更多进程阻塞。

1.2 产生死锁的原因

1. 资源竞争

死锁产生的根本原因,是竞争导致临界资源分配不当。多道程序并发执行,造成多个进程在执行中所需的资源数,大于系统能提供的资源数。
计算机系统中的资源,按照占用方式,可分为两类。
(1)可剥夺资源
某进程在获得这类资源后,即使该进程没有使用完,该类资源也可以被其他进程剥夺使用。例如:CPU、内存、磁盘等
(2)不可剥夺资源
当系统把这类资源分配给某进程后,不能强行收回,只能在进程使用完后自行释放,然后其他进程才能使用。这类资源众多,例如:打印机、刻录机、CD-ROM驱动器等。

​ 对信号量和消息处理不当,也可能会造成死锁。

2.推进顺序不当

​ 并发执行的诸进程在运行中存在异步性,彼此间相对执行速度不定,存在着多种推进顺序。并发进程间推进顺序不当时会引起死锁。
​ 不可剥夺资源少未必一定产生死锁。死锁在一种很巧合的推进顺序中才会发生。在不能增加不可剥夺资源数量的前提下,我们要采取各种措施,尽量避免产生死锁的不合理推进顺序出现。

在这里插入图片描述

在这里插入图片描述

由以上分析,得出两个结论:
(1)用户编写应用程序或OS进行资源分配时,应采取相应措施,避免导致死锁发生的进程间推进顺序的出现。
(2)死锁是在特定的推进顺序中才会出现,具有一定的隐蔽性。
有的死锁隐藏很深,只有在很巧合情况下,导致死锁的推进顺序才会发生。发生死锁的可能性远低于不发生死锁的可能性。软件设计者往往需要花费大量精力去测试程序或系统,才能发现死锁并解决它。

2.死锁的必要条件

​ 死锁发生必须具备一定条件(Coffman条件)。一旦死锁出现,这4个条件都必然成立。因此,只要其中之一被系统或用户破坏掉,就不会出现死锁。四个必要条件是:
(1)互斥条件:某段时间内,多个进程互斥使用某个不可剥夺资源;
(2)请求和保持条件:进程至少已占有一个资源之后,提出新的资源请求。但新资源已被其他进程占用,因而此进程阻塞。阻塞期间,该进程对已获得资源保持不放。参与死锁的进程中至少有两个已占有资源,并申请其他资源。

(3)不剥夺条件:进程已获得的资源在未使用完之前,不能被系统或其他进程剥夺,只能由在使用完毕后由进程自己释放。
(4)环路等待条件:系统中存在一个进程等待序列P1、P2….Pn,其中,P1等待P2占有的某个资源, P2等待P3占有的某个资源,…… Pn等待P1占有的某个资源,从而形成一条进程循环等待环。
环路等待条件隐含着前三个条件,即只有前三个条件成立,第四个条件才会成立。
特别注意:环路等待条件只是死锁产生的必要条件,而不是等价定义。死锁一旦产生则死锁进程间必存在循环等待环,但存在循环等待环不一定产生死锁。

3.死锁的处理

3.1 死锁的处理方法

​ 按死锁处理的时机划分,可把死锁处理方法分成四类。
​ (1)预防死锁
​ (2)避免死锁
​ (3)检测死锁
​ (4)解除死锁

3.2 资源分配图

​ 资源分配图(Resource Allocation Graph)是描述死锁问题的常用工具。资源分配图是一个有向图,该图由结对组成:G=(V,E)。式中V是顶点集,E是边集。
​ 顶点集V由P和R构成,P={P1,P2,┄,Pn}为系统中的进程集合,R={r1,r2,┄,rm}为系统中所有资源类型的集合。
​ 边集E也由两类有向边组成,从进程Pi到资源rj的有向边,记做Pi→rj,代表进程Pi提出申请一个单位的rj资源;从资源rj到进程Pi的有向边,记做rj→Pi,代表一个单位的rj资源已分配给了进程Pi。Pi→rj边被叫申请边;rj→Pi边被叫分配边。
​ 进程用一个圆圈表示,圈内为进程名字。资源类用一个方框表示,方框内的圆点,表示系统中本类资源的个数。

在这里插入图片描述

在这里插入图片描述

4.死锁的静态预防

4.1破坏互斥条件

​ 如系统中所有资源都能共享使用,即破坏死锁的“互斥”使用条件,则系统将不会发生死锁。但临界资源性质决定其不能共享使用,否则无法保证正确性。
​ 在实际系统中,可采用时分或空分虚拟技术,把必须互斥使用的、不可剥夺的独占设备,改造成为可被多个进程共享的虚拟设备,预防死锁的发生。如:采用SPOOLing技术,把打印机改造成虚拟打印机,任何一个想要打印的进程将打印内容先发送到可共享的“输入井”中(磁盘的一个固定区域),发送完毕后,该进程即认为打印完毕,而真正打印输出要等到打印机空闲时才进行。

4.2 破坏请求和保持条件

​ 1、破坏这个条件,可采用预分配资源方法,即:在进程运行前,系统一次性为它分配所需的全部资源。
​ 缺陷:系统无法在进程执行前,精确估计其所需的全部资源,因为进程是一个动态概念,具有不确定性。资源估计少了,仍会存在死锁风险;估计多了,会造成资源浪费。
​ 2、另一种方法:在进程执行前,系统并不把其所需所有资源分配到位,而是进程边执行边申请。但同时规定:在申请新资源失败后,该进程要释放已占用的所有资源。
​ 局限性:进程所使用临界资源,不允许在使用一段时间后随意释放,比如刻录机。某进程在刻录过程中需要访问某台I/O设备,如此时系统不能满足它,则该进程把还没使用完的刻录机资源释放后阻塞,造成它已经刻录的光盘作废。

4.3 破坏不剥夺条件

即:允许进程对系统资源进行抢占,比如CPU、内存。
破坏“不剥夺”条件存在以下主要缺点:
① 系统代价较大。在剥夺用户资源时,要保存进程的上下文现场,进程重新获得资源时,要恢复进程上下文现场。
② 临界资源不可以剥夺。如强行剥夺,会产生不良后果。

4.4 破坏环路等待条件

​ 系统把全部资源事先按类型进行线性排队,并对每类资源赋予不同序号,然后按序进行分配。同时,规定进程不能连续两次申请同类资源。从而进程在申请、占用资源时不会形成资源申请环路,也就不会发生环路等待。

​ 即:系统规定进程必须按资源编号递增顺序申请资源:一个进程最初可申请资源Ri的一个实例,然后它还可继续申请Rj的 一个实例,但Rj的编号必须大于Ri的编号。
​ 如Rj的编号小于Ri的编号,则有两种情况:
(1)申请不能被满足,该进程被阻塞;
(2)该进程释放所有已获得的、编号大于Rj的资源。但此时可能会造成不良后果。
不足:(1)在编程时,用户要牢记所有资源的编号,严格按资源的编号申请资源,增加了用户编程负担。(2)给系统中所有资源合理编号并非易事。

5.死锁的动态避免

5.1 系统安全状态

​ 所谓安全状态指:OS能按某进程执行序列,如<P 1, P2, …,Pn>,为进程分配所需资源,使得每个进程都能执行完毕。此时,执行序列<P1, P2, …,Pn>为当前系统的一个安全序列。
​ 处于安全状态的系统不会产生死锁。即使某进程所需资源总数,超过系统当前可用空闲的资源总数, 它可以等待其他进程执行完毕后释放资源,系统把释放的资源分配给进程 , 从而执行完毕。

在这里插入图片描述

5.2 银行家算法

​ 死锁动态避免策略,就是采取措施防止系统进入不安全状态。银行家算法是典型的安全资源分配方法,
​ 基本思想:在资源分配前,资源分配程序先计算资源分配后,系统是否处于安全状态,如处于则把资源分配给申请进程,否则令申请资源的进程阻塞,不响应其资源申请。
​ 该算法核心理念是:把资源分配给那些最容易执行完成的进程,保证系统中各进程最终都能正常完成。
​ 银行家算法本质是死锁的避免,由于它并没有破坏产生死锁的4个必要条件之一,不属于死锁预防。

​ 银行家有一笔资金M万元,N个客户需要贷款,它们都和银行签订了贷款协议,每个客户所需资金不同但都不超过M万元,但客户们的贷款总和远远超过M万元。协议中规定银行根据自身情况分期向各个客户发放贷款,客户只有在获得全部贷款后,才能在一定时间内将全部资金归还给银行家。银行家并不一定每次都批准客户的贷款请求,在每次发放贷款时,银行家都要考虑发放该笔贷款是否会造成银行无法正常运转,只有在批准贷款请求不会导致银行库存资金不足时,该次贷款请求才会批准。
​ 银行家即OS中的资源分配程序,M万元即系统空闲资源,客户即并发执行的进程,客户贷款金额即进程所需的最大资源数。

​ 基于银行家基本思想,可实现面向多类资源分配的动态避免死锁算法。该算法需要使用的数据结构如下:
​ ① 当前可分配的空闲资源向量–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]
​ 当进程申请资源时,向系统提交一个资源申请向量Requesti[j],如Requesti[j]=k,表示进程申请k个j类资源。
​ 银行家算法按照下述流程进行检查,判断是否把k个j类资源分配给进程 :

当进程Pi申请资源时,向系统提交一个资源申请向量Requesti[ j ],如Requesti[j]=k,表示进程 Pi申请k个j类资源。
银行家算法按下述流程进行检查,判断是否把k个j类资源分配给该进程 :
步骤1:如Requesti[j] + Allocation[i,j] ≤ Max[i,j],转向步骤2;如不成立,说明进程Pi的j类资源申请超过了其最大需求量,报错中断返回。
步骤2:如Requesti[j] ≤ Available[i,j],转向步骤3;如不成立,说明系统中现有的j类资源不能满足进程Pi的资源申请。该请求不能满足,进程Pi 被阻塞,结束算法返回。

​ 步骤3:系统试探着把资源分配给进程 Pi,并修改下面数据结构中的值:
​ Available[i,j] = Available[i,j] - Requesti[j]
​ Allocation[i,j] = Allocation[i,j] + Requesti[j]
​ Need[i,j] = Need[i,j] - Requesti[j]
​ 步骤4:调用系统安全性检查算法,检查此次资源分配后系统是否处于安全状态。若安全,满足进程Pi的资源申请;否则,将本次试探分配作废,恢复原来资源分配状态,不响应进程Pi 的资源申请, 该进程阻塞等待。

在这里插入图片描述

在这里插入图片描述

6.死锁的检测和死锁

6.1 等待图检测死锁

​ 如果系统中资源只有一个,死锁检测可采用资源分配图的变形——等待图。
​ 等待图中,进程Pi到Pj的边,表明Pi在等待Pj释放自己所需的资源。
​ 等待图中,检测算法只要检测出其中存在环路,就意味着存在死锁。

在这里插入图片描述

6.2 多体资源类死锁检测算法

​ 系统中每类资源的实例是多个时,可采用以下死锁检测算法进行检测。该算法采用了和银行家算法类似的数据结构。
​ ①当前可分配的空闲资源向量Available(1:m)。m是系统中的资源类型数。
​ Available[ i ]–表示系统中现有的i类资源数量。
②资源分配矩阵Allocation(1:n,1:m)。
​ Allocation[ i,j ]–表示进程i已占有的j类资源的数量。
③需求矩阵Request(1:n,1:m)。
Request[ i,j ]–表示进程i还需申请j类资源的数量。

死锁检测算法如下:
步骤1、令Work和Finish分别表示长度为m和n的向量,初始化Work=Available;对于所有i =1,…,n,如果Allocation[i]≠0,则Finish[i]=false,否则Finish[i]=true。
步骤2、寻找一个下标i,它满足条件:Finish[i]=false且Request[i]≤Work,如果找不到这样的i,则转向步骤4。
步骤3、Work=Work+Allocation[i];Finish[i]=true;转向步骤2。
步骤4、如果存在i, 1≤i≤n, Finish[i]=false,则系统处于死锁状态。若Finish[i]=false,则进程处于死锁环中。

在这里插入图片描述

在这里插入图片描述

6.3 死锁解除方法

当死锁发生并被检测出来后,必须采取相应措施解除死锁。一种方法是通知系统管理员进行人工干预,另一种是OS自动解除死锁并在适当时机恢复相应进程运行。具体来说,主要有以下三种方式 :
(1)剥夺资源恢复
(2)进程退回
(3)撤销进程

6.4 鸵鸟算法

​ 据说鸵鸟看到危险动物时就把头埋在沙砾中,装作看不到。当人们对某一件事情没有一个很好的解决方法时,或者解决问题的方法代价太大而得不偿失时,人们就借鉴鸵鸟的办法,忽略问题的存在。
​ 在死锁问题上,鸵鸟算法就是不对死锁采取任何处理方法。著名的UNIX、Linux和Windows操作系统在分析了死锁发生的频率、系统因各种原因崩溃的频率、死锁的严重程度以及解决死锁问题的代价之后都采用了鸵鸟算法。

​ 采用鸵鸟算法的代价是用户必须忍受死锁带来的诸多不便。但实际上,经过大量统计,死锁发生的概率是很小的,只有在极偶然的情况下才会出现死锁。
​ 鸵鸟算法也是操作系统设计者处理死锁问题的一种不错选择。

7.线程死锁

在支持多线程的操作系统中.除会发生进程死锁外,还会发生线程的死锁。不同线程可属于同一进程,也可属于不同的进程。因此,与进程死锁比较,线程死锁分为属于同一进程的线程死锁、属于不同进程的线程死锁。

(1)同一进程的线程死锁
线程的同步工具有互斥锁。同一进程的线程共享该进程资源,为实现线程对进程内变量的同步访问,可以采用互斥锁。
(2)不同进程的线程死锁
如在进程P1内存在一组线程{P11,P12,…,P1m},在进程P2内存在一组线程{P21,P22,…,P2n}。同一时间段内,进程P1内的线程获得资源R1,进程P2内的线程获得资源R2。
之后,进程P1内的某个线程P1i请求资源R2,由于不能满足而进入阻塞状态;进程P2内的某个线程P2j请求资源R1,由于不能满足也进入阻塞状态。
线程P1i和线程P2j相互等待对方释放资源,这时出现了不同进程线程间的死锁。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值