Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,93 @@ tag:

注意,只有四个条件同时成立时,死锁才会出现。

### 2.8 解决死锁的方法

#### 那么解决死锁的方法是什么呢?

解决死锁的方法可以从多个角度去分析,一般的情况下,有**预防,避免,检测和解除四种**。

- **预防** 是采用某种策略,**限制并发进程对资源的请求**,从而使得死锁的必要条件在系统执行的任何时间上都不满足。

- **避免**则是系统在分配资源时,根据资源的使用情况**提前做出预测**,从而**避免死锁的发生**

- **检测**是指系统设有**专门的机构**,当死锁发生时,该机构能够检测死锁的发生,并精确地确定与死锁有关的进程和资源。
- **解除** 是与检测相配套的一种措施,用于**将进程从死锁状态下解脱出来**。

#### 死锁的预防

死锁四大必要条件上面都已经列出来了,很显然,`只要破坏四个必要条件中的任何一个就能够预防死锁的发生`。

破坏第一个条件 **互斥条件**:使得资源是可以同时访问的,这是种简单的方法,磁盘就可以用这种方法管理,但是我们要知道,有很多资源**往往是不能同时访问的**,所以这种做法在大多数的场合是行不通的。

破坏第三个条件**非抢占**:也就是说可以采用**剥夺式**调度算法,但剥夺调度方法目前一般仅适用于**主存资源**和**处理器资源**的分配,并不适用于所以的资源,会导致**资源利用率下降**。

所以一般比较实用的**预防死锁的方法**,是通过考虑破坏第二个条件和第四个条件。

- **静态分配策略**:所谓静态分配策略,就是指一个进程必须在执行前就申请到**它所需要的全部资源**,并且知道它所要的资源都得到满足之后才开始执行。这种做法破坏了死锁产生的第二个条件**占有并等待**,进程要么占有所有的资源然后开始执行,要么不占有资源,不会出现占有一些资源等待一些资源的情况。
静态分配策略逻辑简单,实现也很容易,但这种策略**严重地降低了资源利用率**,因为在每个进程所占有的资源中,有些资源是在比较靠后的执行时间里采用的,甚至有些资源是在**额外的情况**下才是用的,这样就可能造成了一个进程占有了一些**几乎不用的资源而使其他需要该资源的进程产生等待**的情况。

- **层次分配策略**:层次分配策略破坏了产生死锁的第四个条件(**循环等待**)。在层次分配策略下,所有的资源被分成了多个层次,一个进程得到某一次的一个资源后,**它只能再申请较高一层的资源**;当一个进程要释放某层的一个资源时,必须先释放所占用的**较高层的资源**,按这种策略,是不可能出现**循环等待链的**,因为那样的话,就出现了已经申请了较高层的资源,反而去申请了较低层的资源,不符合**层次分配策略**,证明略。

#### 死锁的避免

上面提到的**破坏**死锁产生的四个必要条件之一就可以成功**预防系统发生死锁**,但是会导致**低效的进程运行**和**资源使用率**。而死锁的避免相反,它的角度是允许系统中**同时存在四个必要条件**,只要掌握并发进程中与每个进程有关的资源动态申请情况,做出**明智和合理的选择**,仍然可以避免死锁,因为四大条件仅仅是产生死锁的必要条件。

我们将系统的状态分为**安全状态**和**不安全状态**,每当在未申请者分配资源前先测试系统状态,若把系统资源分配给申请者会产生死锁,则拒绝分配,否则接受申请,并为它分配资源。

`安全状态`:如果操作系统能够保证**所有的进程在有限的时间内得到需要的全部资源**,则称系统处于安全状态,否则说系统是不安全的。很显然,`系统处于安全状态则不会发生死锁,系统若处于不安全状态则可能发生死锁`。

那么如何保证系统保持在安全状态呢?通过算法,其中最具有代表性的**避免死锁算法**就是Dijkstra的银行家算法,银行家算法用一句话表达就是,“当一个进程申请使用资源的时候,**银行家算法**通过先**试探**分配给该进程资源,然后通过**安全性算法**判断分配后系统是否处于安全状态,若不安全则试探分配作废,让该进程继续等待,若能够进入到安全的状态,则就**真的分配资源给该进程**”。

银行家算法详情可见[(41条消息) 一句话+一张图说清楚——银行家算法_土豆洋芋山药蛋的博客-CSDN博客_银行家算法](https://blog.csdn.net/qq_33414271/article/details/80245715)

操作系统教程树中讲述的银行家算法也比较清晰,可以一看.

死锁的避免(银行家算法)改善解决了**资源使用率低的问题**,但是它要不断地检测每个进程对各类资源的占用和申请情况,以及做**安全性检查**,需要花费较多的时间。

#### 死锁的检测

对资源的分配加以限制可以**预防和避免**死锁的发生,但是都不利于各进程对系统资源的**充分共享**。解决死锁问题的另一条途径是**死锁检测和解除**(这里突然联想到了乐观锁和悲观锁,感觉死锁的检测和解除就像是**乐观锁**,分配资源时不去提前管会不会发生死锁了,等到真的死锁出现了再来解决嘛,而**死锁的预防和避免**更像是悲观锁,总是觉得死锁会出现,所以在分配资源的时候就很谨慎)。

这种方法对资源的分配不加以任何限制,也不采取死锁避免措施,但系统**定时地运行一个 “死锁检测”**的程序,判断系统内是否出现死锁,如果检测到系统发生了死锁,再采取措施去解除它。

##### 进程-资源分配图

操作系统中的每一刻时刻的**系统状态**都可以用**进程-资源分配图**来表示,进程-资源分配图是描述进程和资源申请及分配关系的一种有向图,可用于**检测系统是否处于死锁状态**。

用一个方框表示每一个资源类,方框中的黑点表示该资源类中的各个资源,每个键进程用一个圆圈表示,用**有向边**来表示**进程申请资源和资源被分配的情况**。约定$P_{i} \rightarrow R_{j}$为请求边,表示线程$P_{i}$申请资源类$R_{j}$中的一个资源**得不到满足**而处于等待$R_{j}$类资源的状态,该有向边从进程开始指到方框的边缘,表示进程$P_{i}$申请$R_{j}$类中的一个资源。反之,$R_{j}\rightarrow P_{i}$为**分配边**,表示R的一个资源分配给了P。

图中2-21是**进程-资源分配图**的一个例子,其中公有三个资源类,每个进程的资源占有和申请情况已清楚地表示在图中。在这个例子中,由于存在**占有和等待资源的环路**,导致一组进程永远处于等待资源的状态,**发生了死锁**。

<img src="https://github.com/zhengjianda/JavaGuide/blob/main/docs/cs-basics/operating-system/images/%E8%BF%9B%E7%A8%8B-%E8%B5%84%E6%BA%90%E5%88%86%E9%85%8D%E5%9B%BE.jpg" height="300"></img>


进程-资源分配图中存在环路**并不一定是**发生了死锁。因为循环等待资源仅仅是死锁发生的必要条件,而不是充分条件。图2-22便是一个有环路而无死锁的例子。虽然进程P1和进程P3分别占用了一个资源R1和一个资源R2,并且因为等待另一个资源R2和另一个资源R1形成了环路,但进程P2和进程P4分别占有了一个资源R1和一个资源R2,它们申请的资源得到了满足,在有限的时间里会归还资源,于是进程P1或P3都能获得另一个所需的资源,环路自动解除,系统也就不存在死锁状态了。

##### 死锁检测步骤:

知道了死锁检测的原理,我们可以利用下列步骤编写一个**死锁检测**程序,检测系统是否产生了死锁。

1) 如果进程-资源分配图中无环路,则此时系统没有发生死锁
2) 如果进程-资源分配图中有环路,且每个资源类仅有一个资源,则系统中已经发生了死锁。
3) 如果进程-资源分配图中有环路,且涉及到的资源类有多个资源,此时系统未必会发生死锁。如果能在进程-资源分配图中找出一个**既不阻塞又非独立的进程**,该进程能够在有限的时间内归还占有的资源,也就是把边给消除掉了,重复此过程,直到能在有限的时间内**消除所有的边**,则不会发生死锁,否则会发生死锁。(消除边的过程类似于**拓扑排序**)

#### 死锁的解除

当死锁检测程序检测到**存在死锁发生时**,应设法让其解除,让系统从死锁状态中恢复过来,常用的解除死锁的方法有以下四种:

1. **立即结束所有进程的执行,重新启动操作系统**

这种方法简单,但以前所在的工作全部作废,损失很大。

2. **撤销涉及死锁的所有进程**,解除死锁后继续运行

这种方法能彻底打破**死锁的循环等待**条件,但将付出很大代价,例如有些进程可能已经计算了很长时间,由于被撤销而使产生的部分结果也被消除了,再重新执行时还要再次进行计算。

3. 逐个撤销涉及死锁的进程,回收其资源直至死锁解除。

4. 抢占资源:从涉及死锁的**一个或几个进程**中抢占资源,把夺得的资源再分配给涉及死锁的进程直至死锁解除。

## 三 操作系统内存管理基础

### 3.1 内存管理介绍
Expand Down