死锁(三)
文章目录
资源
当若干进程取得对设备、文件等资源的独占性访问权时,就可能出现死锁。简单地说,资源是在任何时刻都只能被一个进程使用的任何对象。资源被划分为可抢占资源和不可抢占资源。
死锁概念
死锁:是指两个或两个以上的进程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去。此时系统处于死锁状态或系统产生了死锁。
多数情况下,进程是在等待该集合中另一个进程释放其所占有的资源。也就是说,每个进程都在期待获得另一个进程正在占用的资源。由于集合中的所有进程都不能运行,因而谁也不会释放资源。计算机系统产生死锁的根本原因就是资源有限且操作不当
死锁出现的四个必要条件(同时具备以下四个)
-
互斥条件
- 独占资源在一段时间内只能由一个进程占有,不能同时被两个及其以上的进程占有。例如,平板式绘图仪、CD-ROM驱动器、打印机等。必须在占有该资源的进程主动释放它之后,其他进程才能占有该资源。这是由资源本身的属性所决定的。
-
占有且等待条件
- 进程至少已经占有一个资源,但又申请新的资源。由于该资源已被另外进程占有,此时该进程阻塞。但是它在等待新资源时,仍继续占有已分到的资源。
-
不可抢占条件
- 一个进程所占有的资源在用完之前,其他进程不能强行夺走该资源,只能由该进程用完之后主动释放。
-
循环等待条件
存在一个进程等待序列{p1,p2,p3,…,pn},其中p1等待p2所占用有的某个资源,p2等待p3所占有的某个资源,…,而pn等待p1所占有的某个资源,从而形成一个进程循环等待环。
处理死锁的方法
- 利用某些协议预防或避免死锁,保证系统不会进入死锁状态。
- 允许系统进入死锁状态,然后设法发现并解除它。
- 完全忽略这个问题,好像系统中从来也不会出现死锁。在多数操作系统中都这样做,包括UNIX系统。
死锁的预防
- 破坏互斥条件
- 一方面,独占资源必定具有互斥条件。例如,一台打印机不能同时被多个进程使用。另一方面,可共享的资源不需要互斥存取,它们不会包含在死锁之中。如只读文件就是可共享资源的例子。打开的只读文件可以被若干进程同时存取。一个进程从来也不会在一个可共享资源上一直等待下去。然后,一般来说,用否定互斥条件的办法是不能预防死锁的,因为某些资源固有的属性就是独占的。
- 破坏占有且等待条件
- 为使系统从来不会出现“占有且等待”条件,需要保证一个进程无论什么时候都可以申请它没有占有的任何其他资源。一种办法是预分资源策略,即一个进程开始执行之前就申请并分到所需的全部资源,从而它在执行过程中就不再需要申请另外的资源。由于预先就为它把所需资源都准备好了,从而保证他能运行到底。在实现时,一个进程申请资源的系统调用要先于其他的系统调用。这就是资源的静态分配。
- 另一种办法是“空手”申请资源策略,即每个进程仅在它不占有资源时才可以申请资源。一个进程可能需要申请并使用某些资源,在它们申请另外附加资源之前,必须先释放当前分到的全部资源。
- 破坏非抢占条件
- 产生死锁的第三个必要条件是对已分配资源的非抢占式分配,为了破坏这个条件,可以采用下述隐式抢占方式:如果一个进程占有某些资源,它还要申请被别的进程占有的资源,该进程就一定处于等待状态,这时,该进程当前所占有的全部资源可被抢占。也就是说,这些资源隐式地释放了,在该进程的资源申请表中加上刚被剥夺的资源。仅当该进程获得它被剥夺的资源和新申请的资源时,它才能重新启动。
- 另一种方法是抢占等待者的资源。若一个进程申请某些资源,首先应检查它们是否可供使用。如果可用,就分给该进程;如果它们不可用,就要查看:它们是否已分给另外某个正常等待附加资源的进程。若是这样的话,就把所需资源从等待进程那儿抢占过来,分给申请它们的进程。如果该资源不可用,即没有被等待进程占有,那么申请进程必须等待。当该进程等待时,它的某些资源可被抢占过去,但是这仅在另外的进程需要它们的时候才被抢占。仅当一个进程分到它所需的新资源并且恢复在它等待期间被抢占去的所有资源的情况下,它才重新启动。
- 破坏循环等待条件
- 为了不出现循环等待条件,一种方法是实行资源有序分配策略,即把全部资源事先按类编号,然后依序分配,使进程申请、占用资源时不会形成环路。
死锁的避免
安全序列
所谓安全序列,就是指如果系统按照这种序列分配资源,则每个进程都能顺利完成。只要能找出一个安全序列,系统就是安全状态,当然,安全序列可能有多个。
如果分配了资源之后,系统中找不出任何一个安全序列,系统就进入了不安全状态。这就意味着之后可能所有进程都无法顺利的执行下去。当然,如果有进程提前归还了一些资源,那系统也有可能重新回到安全状态,不过我们在分配资源之前总是要考虑最坏的情况。
银行家算法
银行家算法是荷兰学者Dijkstra为银行系统设计的,以确保银行在发放现金贷款时,不会发生不能满足所有客户需要的情况。后来该算法被用在操作系统中,用于避免死锁。
核心思想:在进程提出资源申请时,先预判此次分配是否会导致系统进入不安全状态。如果会进入不安全状态,就暂时不答应这次请求,让该进程先阻塞等待。
银行家算法的本质:要设法保证系统动态分配资源后不进入不安全状态,以避免可能产生的死锁。
即:每当进程提出资源请求且系统的资源能够满足请求时,系统将判断如果满足此次资源请求,系统状态是否安全,如果判断结果为安全,则给该进程分配资源,否则不分配资源,申请资源的进程将阻塞。
银行家算法所需数据结构:
- 长度为m的一堆数组Available表示还有多少可用资源
- n*m矩阵Max表示各进程对资源的最大需求数
- n*m矩阵Allocation表示已经给各进程分配了多少资源
- Max - Allocation = Need 矩阵表示各进程最多还需要多少资源
- 用长度为m的一位数组Request表示进程此次申请的各种资源数
银行家算法步骤:
- 检查此次申请是否超过了之前声明的最大需求数
- 检查此时系统剩余的可用资源是否还能满足这次请求
- 试探着分配,更改各数据结构
- 用安全性算法检查此次分配是否会导致系统进入不安全状态
安全性算法步骤:
- 检查当前剩余可用资源是否能满足某个进程的最大需求,如果可以,就把该进程加入安全序列,并把该进程持有的资源全部回收。
- 不断重复上述过程,看最终是否能让所有进程都加入安全序列。
注意:银行家算法从避免死锁的角度上说是非常有效的,但是,从某种意义上说,它缺乏实用价值,因为很少有进程能够在运行前就知道其所需资源的最大值,而且进程数也不是固定的,往往在不断地变化(如新用户登录或退出),况且原本可用的资源也可能突然间变成不可用(如磁带机可能坏掉)。因此,在实际中,如果有,也只有极少的系统使用银行家算法来避免死锁。
死锁的检测和恢复
一般来说,由于操作系统有并发、共享及随机性等特点,通过预防和避免的手段达到排除死锁的目的是很困难的。这不仅需要较大的系统开销,而且也不能充分利用资源。一种简便的办法是系统为进程分配资源时,不采取任何限制性措施,但是提供检测和解脱死锁的手段,既能发现死锁,并从死锁状态中解脱出来。因此,在实际的操作系统中,往往采用死锁的检测与恢复方法来排除死锁。
对单体资源类的死锁检测
如果系统中所有类型的资源都只有一个单位,可以采用一种较快的死锁检测算法,即资源分配图的变形——等待图。它是从资源分配图中去掉资源类的节点,且把相应边折叠在一起得到的。
对多体资源类的死锁检测
等待图并不适合用于多体资源类的资源分配系统。针对多体资源类可以采用下面的死锁检测算法。这个检测算法采用若干随时间变化的数据结构,与银行家算法中所用的结构相似。
从死锁中恢复
当利用检测算法发现死锁后,必须采取某种措施使系统从死锁中解脱出来。方法有多种,如人工干预——当发现死锁时就通知系统管理员,让管理员解决死锁问题:或者由系统自动从死锁中恢复过来。具体来说,主要有三种方式:通过抢占资源、回退执行和杀掉进程的实现恢复。
措施使系统从死锁中解脱出来。方法有多种,如人工干预——当发现死锁时就通知系统管理员,让管理员解决死锁问题:或者由系统自动从死锁中恢复过来。具体来说,主要有三种方式:通过抢占资源、回退执行和杀掉进程的实现恢复。