【操作系统】死锁相关知识点

1. 死锁基本概念

多个并发进程中,如果每个进程持有某种资源而又等待其它进程释放其他资源,在未改变这种状态之前都不能向前推进,称这一组进程产生了死锁。通俗的讲就是 多个进程无限期相互等待 的一种状态。

2. 死锁的四个必要条件

死锁产生的 4 个条件(有一个条件不成立,则不会产生死锁):

  • 互斥:一个资源一次只能被一个进程使用
  • 请求与保持:一个进程因请求资源而阻塞时,对已获得资源保持不放
  • 非抢占:进程获得的资源,在未完全使用完之前,不能强行抢占
  • 循环等待:若干进程之间形成一种头尾相接的环形等待资源关系

抢占资源和非抢占资源:

  • 可抢占资源:可以从拥有它的进程中抢占而不产生副作用。
  • 不可抢占资源:不引起相关的计算失败的情况下,无法把它从占有它的进程处抢占过来。

一般来说,可抢占资源不会引起死锁,可以在进程间重新分配资源而得到解决。

资源分配图(RAG):用有向图描述系统资源和进程的状态。
在这里插入图片描述
进程 P1 已经分得了两个 R1 资源,并又请求一个 R2 资源;进程 P2 分得了一个 R1 和一个 R2 资源,并又请求一个 R1 资源。

死锁发生时,系统中一定有由两个或以上的进程组成的一条环路,该环路中的每个进程都在等待着下一个进程所占有的资源。用一个有向图来表示资源分配的情况。用圆形节点表示进程,方形表示资源。从 资源节点到进程节点的有向边表示该资源被请求、并被进程占用,从 进程到资源节点的有向边表示进程正在请求该资源,并且因为请求资源而导致进程被阻塞,处于等待该资源的状态。一旦在某个时候有向图中出现了 两个或两个以上进程组成的环路,就会导致死锁的发生。

死锁定理:如果资源分配图中没有环路,则系统中没有死锁,如果图中存在环路则系统中可能存在死锁;如果每个资源类中只包含一个资源实例,则环路是死锁存在的充分必要条件。
在这里插入图片描述

3. 死锁处理方法

死锁的四个处理方法:

  • 鸵鸟策略:忽略掉死锁,视而不见
  • 死锁检测与恢复:允许死锁发生,检测它们是否发生,一旦发生死锁,就采取行动解决问题
  • 死锁避免:仔细对资源进行分配,动态地避免死锁,银行家算法是避免死锁的经典算法
  • 死锁预防:破坏引起死锁的 4 个必要条件

3.1 鸵鸟策略

把头埋在沙子里,假装根本没发生问题。

因为解决死锁问题的代价很高,因此鸵鸟策略这种不采取任务措施的方案会获得更高的性能。

当发生死锁时不会对用户造成多大影响,或发生死锁的概率很低,就可以采用鸵鸟策略。

大多数操作系统,包括 Unix,Linux 和 Windows,处理死锁问题的办法仅仅是忽略它。

3.2 死锁检测与恢复

不试图阻止死锁,而是当检测到死锁发生时,采取措施进行恢复。

死锁检测:

  • 每种类型一个资源的死锁检测:检测有向图中是否存在环。从一个节点出发进行深度优先搜索,对访问过的节点进行标记,如果访问了已经标记的节点,就表示有向图存在环,也就是检测到了死锁。
  • 每种类型多个资源的死锁检测:每个进程最开始时都不被标记(未执行状态),执行过程有可能被标记。当算法结束时,任何没有被标记的进程都是死锁进程。

三个典型的检测时机:

  • 当进程由于资源请求不满足而等待时检测死锁,缺点是系统开销大
  • 定时检测
  • 系统资源利用率下降时检测死锁

每种类型多个资源的死锁检测算法:

  1. 寻找一个没有标记的进程 Pi,要求它所请求的资源小于等于剩余资源量。
  2. 如果找到了这样一个进程,就将其占有的资源量加到剩余资源量中,并标记该进程,转回第 1 步。
  3. 如果没有找到这样一个进程,说明发生死锁。

死锁恢复:

  • 抢占恢复(资源剥夺):死锁发生的必要条件,其中一个就是不可抢占。如果允许抢占,那么就可以破坏死锁条件。
  • 回滚恢复(进程回退):周期性对进程进行检查点检查,一旦发现了死锁,就回滚到一个较早的检查点上。
  • 杀死进程恢复(撤销进程):杀死一个进程可以释放它占有的资源,如果仍然不行那么久继续杀死其他进程直到打破死锁。

3.3 死锁避免

在程序运行时避免发生死锁,包括两种方法:1)资源轨迹图,2)银行家算法。

1. 资源轨迹图

如果知道了进程在各个阶段需要哪些资源,那么可以在图中进程标注。两个进程的交叠区域就是一个会造成死锁的区域。进程在图中只能向右或者向上前进,一旦进入了危险区,那么就可能发生死锁。为了避免死锁,应当在合适的时间阻塞某个进程,使得运行避开这个区域。

2. 银行家算法

银行家算法的主要思想是避免系统进入不安全状态。在每次进行资源分配时,它首先检查系统是否有足够的资源满足要求,如果有,则先进行分配,并对分配后的新状态进行安全性检查。如果新状态安全,则正式分配上述资源,否则就拒绝分配上述资源。这样,它保证系统始终处于安全状态,从而避免死锁现象的发生。

安全状态

如果没有死锁发生,并且即使所有进程突然请求对资源的最大需求,也仍然存在某种调度次序能够使得每一个进程运行完毕,则称该状态是安全的(安全状态一定没有死锁发生)。
在这里插入图片描述
安全状态与不安全状态的区别是,从安全状态出发,系统能够保证所有的进程都能完成;而从不安全状态出发,没有这样的保证。

单个资源的银行家算法

一个小城镇的银行家,他向一群客户分别承诺了一定的贷款额度,算法要做的是对每一个请求进行检查,检查如果满足了这一需求是否会达到安全状态。如果能,那么满足该需求;如果不能,就推迟对这一请求的满足。

银行家算法可以推广到多个资源的情况,此时可以写成矩阵的形式,每次判断一行是否满足,即一个进程的多个资源都进行检查。

多个资源的银行家算法

检查一个状态是否安全的算法:

  • 查找右边的矩阵是否存在一行小于等于向量 A。如果不存在这样的行,那么系统将会发生死锁,状态是不安全的。
  • 假若找到这样一行,将该进程标记为终止,并将其已分配资源加到 A 中。
  • 重复以上两步,直到所有进程都标记为终止,则状态时安全的。

如果一个状态不是安全的,需要拒绝进入这个状态。

实际上,死锁避免是非常困难的,无论是资源轨迹图还是银行家算法,都需要事先知道进程运行的过程中需要的最大资源数,这几乎是不可能实现的。

3.4 死锁预防

死锁预防就是在程序运行之前预防发生死锁,即破坏发生死锁的 4 个必要条件。死锁避免可以认为是在程序执行中动态地避免死锁发生,而死锁预防可以说是静态的方式,杜绝死锁发生的可能性。

1. 破坏互斥条件:尽量使得资源不被某个进程独占。

但有些资源不能同时访问,如打印机等临界资源只能互斥使用。所以在某些场合应该保护这种互斥性。

2. 破坏占有和等待条件:禁止已经持有资源的进程再等待其他资源。一种方式是,在进程开始执行前请求所需的全部资源(预先静态分配的方法),如果不能满足,那么就不分配资源,进行等待。这种方式的问题在于,类似银行家算法,事先不知道需要多少资源,而且资源利用率不高。另一种方式就是,当一个进程请求资源时,先暂时释放其当前所占用的所有资源,然后再尝试一次获取所需的全部资源。

这种方式实现简单,但缺点也显而易见,系统资源被严重浪费,其中有些资源可能仅在运行初期或运行快结束时才使用,甚至根本不使用。而且还会导致“饥饿”现象,当由于个别资源长期被其他进程占用时,将致使等待该资源的进程迟迟不能开始运行。

3. 破坏不可抢占条件:允许资源抢占即可。当然,有的时候资源应当是不可抢占的。

该策略释放已获得的资源可能造成前一阶段工作的失效,反复地申请和释放资源会增加系统开销,降低系统吞吐量。这种方法常用于状态易于保存和恢复的资源,如 CPU 的寄存器及内存资源,一般不能用于打印机之类的资源。

4. 破坏环路等待:一种方法是对资源进行编号,进程在任何时候都可以请求资源,但是所有的请求必须按照资源编号的顺序(升序)提出。

这种方法存在的问题是,编号必须相对稳定,这就限制了新类型设备的增加;尽管在为资源编号时已考虑到大多数作业实际使用这些资源的顺序,但也经常会发生作业使甩资源的顺序与系统规定顺序不同的情况,造成资源的浪费;此外,这种按规定次序申请资源的方法,也必然会给用户的编程带来麻烦。

3.5 死锁处理策略比较

资源分配策略模式优点缺点
死锁检测宽松,只要允许就分配资源定期检查死锁是否已经发生不延长进程初始化时间,允许对死锁进行现场处理
死锁避免是”预防“和”检测“ 的折中(在运行时判断是否可能死锁)寻找可能的安全允许顺序不必进行剥夺
死锁预防保守,宁可资源闲置一次请求所有资源,资 源剥夺,资源按序分配适用于做突发式处理的进程,不必进行剥夺

4. 其他相关

4.1 活锁

活锁指进程并没有被阻塞,但由于某些条件没有满足,导致一直重复尝试、失败、尝试、失败。进程仍可以在 CPU 上活动,但 CPU 时间片执行完了之后又下了 CPU,进程没有任何进展但也没有阻塞。

活锁和死锁的区别:

  • 活锁有可能自行解开,而死锁不能
  • 活锁有 CPU 执行权,而死锁进程是无法获得 CPU 执行权的

4.2 饥饿

饥饿:进程无限等待的情况。饥饿 ≠ 死锁,但是饥饿至少有一个进程的执行被无限期推迟。

产生饥饿的原因:往往是由于资源分配策略的 “不公平性” 导致的,比如短作业优先。此时系统虽然没有发生死锁,某些进程也可能会一直得不到 CPU 的使用权而长时间等待。当 “饥饿” 到一定程度,进程任务即使完成也不再具有实际意义时称该进程被 “饿死”。

饥饿与死锁都是由于 资源竞争 而引起的。

饥饿与死锁的差别

  • 进入“饥饿”状态的进程可以只有一个,而由于循环等待条件而进入死锁状态的进程却必须大于或等于两个。
  • 处于“饥饿”状态的进程可以是一个就绪进程,如静态优先权调度算法时的低优先权进程,而处于死锁状态的进程则必定是阻塞进程。
  • 死锁进程等待的是永远不会被释放的资源,而饿死进程等待的是会释放但不会分配给自己的资源。
  • 死锁一定发生了循环等待,而饿死不一定。可以通过资源分配图检测是否死锁,但不能检测是否有进程饿死。

4.3 通信死锁

当一个进程 A 向 B 发送信息后挂起,需要 B 进程的回复唤醒时,如果请求信息丢失,A 就会被阻塞以等待回复,B 会阻塞等待一个向其发送命令的请求,因而发生死锁。

4.4 两阶段加锁

这是针对数据库的一种方法。第一阶段中,进程试图对 所有需要更新的记录 进行加锁,一旦某个记录已经被加锁,就释放之前的锁,从头进行重试。只有当第一阶段所有获取锁的行为都成功,才进行第二阶段的更新,否则放弃所有的锁。


参考文章:
《计算机操作系统》总结五(死锁)
死锁 作者:luStar
CS-Notes:死锁

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

不吃饭就会放大招

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值