可重用性资源是指可供用户重复使用多次的资源,它具有以下特点:
对资源的请求和释放通常是通过系统调用完成的;
消耗性资源又称为临时性资源,它是在进程运行期间由进程动态创建和消耗的,它具有以下特点:
可消耗性资源通常由创建者进程创建,由消耗者进程使用;
死锁的起因通常是对多个资源的争夺,不仅对不可抢占资源的争夺会引起死锁,对可消耗资源的争夺也会引起死锁
死锁,可以定义为一组进程中的每一个进程都在等待只有这组进程中的进程才能触发的事件;
只要破坏四个条件中的一个,就能阻止死锁情况的发生;
处理死锁的方法一般分为四种
上述四种方法,从上到下对死锁的防范程度越来越低,但是对应的资源利用率越来越高,以及进程因资源因素被阻塞的频度越来越低(即并发程度提高);
预防死锁通常是破坏死锁产生的必要条件之一;由于互斥是并发状态下对临界资源的访问方式,不但不能破坏还必须遵守,所以只能破坏后面三个条件;
破坏“请求和保持条件”
为了能破坏该条件,需要保证当进程在请求资源时,它不能持有不可抢占资源;通常有两种方法:
第一协议:所有进程在开始运行之前,必须一次性申请它在运行时需要用到的资源,只要有一个资源不满足,那么它就不能获得任何资源;这样,如果系统有足够的资源,那么进程在运行之前就可以获得需要的全部资源,运行中自然也就不请求其他资源了,即破坏了请求条件;如果进程需要的资源不能被满足,那么它就不能获得任何资源,这样当进程在等待状态时自然有就没有“持有”任何资源了;
优点是简单、易行;这种方式的缺点很明显:首先资源被严重浪费,一个进程可能长期拥有一个只使用一小会的资源或者在开始就拥有一个只有到结束才可能用到的资源,这于资源来讲是极大的浪费;进程会经常发生饥饿现象,由于某些资源被其他进程长期占用,所以即便该资源对于某一个进程来说只有最后才会用到,该进程也不得不一直阻塞;
第二协议:进程一开始可以不必获得所有的资源才能运行,但是在进程的运行过程中需要逐步释放分配给自己的且已使用完毕的资源,然后才能继续申请其他所需要的新资源;这样做的好处是,不仅能更快地完成任务,提高设备的利用率,还可以避免进程发生饥饿现象;但是该方法实现比较复杂。
破坏“不可抢占条件”
当一个进程在申请某一资源时,如果该请求不能被满足,那么该进程则释放自己已持有的所有资源;这种方法不但实现比较复杂,而且可能会因为反复申请和释放资源导致一些进程的执行无限期推迟,不仅延长了进程的周转时间,而且也增加了系统开销,降低了系统吞吐量;
破坏“循环等待条件”
一个能保证“循环等待条件”不满足的策略是:对所有系统资源类型进行编号并线性排序,进程按照序列号递增的顺序申请资源;当进程所持有的最大资源号为x时,当且仅当A资源的序号y>x时该进程才能申请A资源;如果进程申请A资源,但是y<x,那么进程就需要释放自己持有的所有序号大于y的资源;采用这种资源分配方式所形成的资源分配图中不可能出现环路,所以也就破坏了循环等待的条件;
采用这种资源分配方式,一个问题就是对资源类型的编号需要符合大多数进程使用资源的顺序,比如依据输入-计算-输出这一顺序,输入设备应该具有较低的类型号;此种方法相比其他几种方法来说,系统资源利用率和系统吞吐量均得到提高,但是也存在以下问题:1、扩充资源类型不便;2、存在一些进程,使用资源的顺序与系统规定的资源类型序号的策略不同,这样可能造成资源的浪费;3、这种方法对于编程增加了额外的限制;
避免死锁也是一种预防策略,但是并不是事先采取某种措施,破坏死锁的必要条件,而是在进行资源分配时防止系统进入不安全状态以避免产生死锁现象。由于这种方法所施加的限制条件较弱,所以系统有较好的性能,目前普遍采用这种方式;
在死锁避免方法中,系统有两种状态:安全状态和不安全状态;当系统处于安全状态时,可以避免进入死锁;当系统处于不安全状态时,有可能进入死锁;
安全状态与非安全状态:所谓安全状态,是指系统能按照某种进程推进方式(某个进程序列)为每个进程分配其所需的资源,直至满足每个进程对资源的最大需求,使每个进程都可以顺利地完成;如果找到这样一个序列,则系统是处于安全状态;否则系统处于不安全状态;虽然系统处于不安全状态时不一定进入死锁,但是是存在这个可能的;因此避免死锁的实质在于,系统进行资源分配时,应使系统不进入不安全状态;
在建立了系统安全状态的概念之后,便可知避免死锁的基本思想就是确保系统始终处于安全状态;当有进程请求一个可用资源时,系统需要对该进程的请求进行计算,如果将资源分配给进程之后,系统仍然处于安全状态,那么该资源才可以分配给进程;否则不进行分配;
避免死锁的最有代表性的算法就是DijKstra的银行家算法。该算法涉及的数据结构以及伪算法如下:
银行家算法涉及的数据结构:
银行家算法的伪算法:
设request是编号为x的进程的请求向量;如果request[j]=k,表示进程x对编号为j的资源请求量为k;
如果request[j]<=need[x,j],转向2;否则请求出错,因为它申请的资源数量超过当前它需要的数量,认为这是一个失败的请求;
如果request[j]<=Available[j],转向3;否则表示系统当前没有足够的资源可以分配,x进程需要等待;
试着将编号为j的资源分配给进程x,更新相关数据结构:
Available[j]=Available[j]-request[j];
Allocation[x,j]=Allocation[x,j]+request[j];
Need[x,j]=Need[x,j]-request[j];
进入安全性检测程序(该程序试图找到一个安全序列;如果找到,说明这次分配之后系统仍然是安全的,否则这次分配无效,因为系统进入了不安全状态)
安全性检测程序数据结构及其伪算法
设置两个向量:工作向量Work,表示系统可提供给进程继续运行所需的各类资源数目;初始值为Available;Finish[j]表示编号为j的进程是否有足够资源,使之完成运行;初始值为false;当有足够资源时设置为true;
从进程中找到一个满足下述条件的进程:
1) Finish[j]=false;2)Need[x,j]<=work[j];如果找到执行步骤3;否则执行4;
当进程x获得资源后,可顺利执行完毕,所以将归还分配给它的资源,所以执行:
Work[j]=Work[j]+Allocation[x,j];
Finish[x]=true;
go to 2;
如果所有进程的Finish[j]=true,则表示系统处于安全状态;则上次的资源分配可以进行;否则,不行啊;
到这里我就想到一个问题,如果2中满足条件的有多个,那么是否可以任意选择呢?正当我码这些字的时候,我想通了:是可以的!因为一旦选择完一个进程后,就假设该进程执行完毕,那么它就要归还系统资源,即系统资源是不减的!也就是说,如果在某一次查找中,有x个进程满足条件,那么任意选择一个进程并且执行完3后再回到2时,原来满足条件的进程现在一定还是满足的,原来不满足的进程由于资源的不减,也有可能满足,所以,是可以任意选择的!
如果系统中既没有死锁预防措施也没有死锁避免措施,那么系统很有可能发生死锁;在这种情况下,需要系统提供以下两种算法:死锁检测算法和死锁解除算法;
死锁检测算法:为实现死锁检测算法,需要系统记录各种资源的使用情况以及进程对资源的请求情况,并且系统需要能根据这些信息检测系统是否进入死锁状态;一种常见的死锁检测方法是利用资源分配图。
资源分配图是这样的有向图:它包含两类节点(资源节点和进程节点)和两类边(资源请求边,由进程节点出发,指向资源节点;资源分配边,由资源节点指向进程节点);利用资源图分配图检测死锁的原理如下:
在资源分配图中找到一个既不阻塞也不独立的进程节点,然后为其分配所需的全部资源,使其得以运行结束,再释放其所占有的全部资源,这相当于消去所有经过该进程节点的边使之成为一个独立的点,然后更新资源数量;然后重复这个步骤;如果经过一系列简化后,所有边都被消去,即所有节点都是孤立的,那么系统就没有死锁;否则系统就是死锁状态;这一定理也被称为死锁定理;
这里,不同的简化顺序最后得到的简化图是一样的,道理同上面提到的一样,因为每简化一次,资源数目是不减的;
死锁解除算法:死锁解除常使用两种方法:抢占资源和终止进程;
终止进程的方法有一次性终止所有死锁进程,效果立竿见影,但是也意味着功亏一篑:许多进程都需要从头再来,并且有些情况下,数据可能无法还原,从而造成极大的破坏;还有就是逐个终止进程,释放资源,直到打破循环等待,将系统从死锁中解决出来;但是这里存在一个问题,该如何选择要终止的进程?常常需要考虑以下几点:
一种最小代价的死锁解除算法是:对于死锁状态的每一个进程,都计算一遍终止该进程所产生的代价,然后选择代价最小的一个进程终止,然后如果系统还处于死锁,那么重复前一个步骤;但是计算选择代价最小的进程这一步骤可能会有较大的代价!总体来说,还是让系统别进入死锁的好!对吧!把死锁扼杀在摇篮里!
本文发布于:2025-03-22 13:57:00,感谢您对本站的认可!
本文链接:https://www.4u4v.net/it/1742623038583255.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
留言与评论(共有 0 条评论) |