死锁问题

1, 什么是死锁?

2, 死锁是如何产生的?

3, 如何避免死锁?


1. 什么是死锁

死锁的规范定义
  • 集合中的每一个进程都在等待只能由本集合中的其他进程才能引发的事件,那么该组进程是死锁的。

一种情形

  • 执行程序中两个或多个线程发生永久堵塞(等待)
  • 每个线程都在等待被其他线程占用并堵塞了的资源。

例如

  • 如果线程A锁住了记录1并等待记录2,而线程B锁住了记录2并等待记录1,这样两个线程就发生了死锁现象

通俗点来讲

  • 比如两个人吃饭只有一双筷子
  • 一个人拿左筷子, 一个人拿右筷子,两个人都在等对方的筷子, 这样两个人都没办法吃饭, 就造成了死锁

这种情况可能发生在

  • 当两个线程尝试获取其他资源的锁,而每个线程又陷入无限等待其他资源锁的释放时,除非一个用户的进程被终止,否则就会产生死锁

线程死锁可能发生在以下的情况

  • 当两个线程相互调用int pthread_join(pthread_t thread, void **retval);
  • 当两个线程使用嵌套的同步块时,一个线程占用了另一个线程必需的锁,互相等待时被阻塞,就有可能出现死锁
死锁的危害

说了半天, 死锁究竟会产生什么后果呢?

当出现死锁时,进程永远不能完成,并且阻碍使用系统资源,阻止了其他作业开始执行,导致系统的资源利用率急剧下载,下面列举出一些比较直接的影响。

  • 死锁会使进程得不到正确的结果。因为处于死锁状态的进程得不到所需的资源,不能向前推进,故得不到结果。
  • 死锁会使资源的利用率降低。因为处于死锁状态的进程不释放已占有的资源, 以至于这些资源不能被其他进程利用,故系统资源利用率降低。
  • 死锁还会导致产生新的死锁。其它进程因请求不到死锁进程已占用的资源而无法向前推进,所以也会发生死锁。

所以进程出现了死锁,有可能产生多米诺骨牌效应,最终会导致操作系统崩溃!


2. 死锁产生的原因

1)竞争资源引起进程死锁

当系统中供多个进程共享的资源如打印机、公用队列的等,其数目不足以满足诸进程的需要时,会引起诸进程对资源的竞争而产生死锁。

2)可剥夺资源和不可剥夺资源

系统中的资源可以分为两类

  • 一类是可剥夺资源,是指某进程在获得这类资源后,该资源可以再被其他进程或系统剥夺。例如,优先权高的进程可以剥夺优先权低的进程的处理机。又如,内存区可由存储器管理程序,把一个进程从一个存储区移到另一个存储区,此即剥夺了该进程原来占有的存储区,甚至可将一进程从内存调到外存上,可见,CPU和主存均属于可剥夺性资源。
  • 另一类资源是不可剥夺资源,当系统把这类资源分配给某进程后,再不能强行收回,只能在进程用完后自行释放,如磁带机、打印机等。

3)竞争不可剥夺资源

在系统中所配置的不可剥夺资源,由于它们的数量不能满足诸进程运行的需要,会使进程在运行过程中,因争夺这些资源而陷于僵局。
例如,系统中只有一台打印机R1和一台磁带机R2,可供进程P1和P2共享。假定PI已占用了打印机R1,P2已占用了磁带机R2,若P2继续要求打印机R1,P2将阻塞;P1若又要求磁带机,P1也将阻塞。
于是,在P1和P2之间就形成了僵局,两个进程都在等待对方释放自己所需要的资源,但是它们又都因不能继续获得自己所需要的资源而不能继续推进,从而也不能释放自己所占有的资源,以致进入死锁状态。

4)竞争临时资源

上面所说的打印机资源属于可顺序重复使用型资源,称为永久资源。
还有一种所谓的临时资源,这是指由一个进程产生,被另一个进程使用,短时间后便无用的资源,故也称为消耗性资源,如硬件中断、信号、消息、缓冲区内的消息等,它也可能引起死锁。例如,S1,S2,S3是临时性资源,进程P1产生消息S1,又要求从P3接收消息S3;进程P3产生消息S3,又要求从进程P2处接收消息S2;进程P2产生消息S2,又要求从P1处接收产生的消息S1。
如果消息通信按如下顺序进行

  • P1: ···Relese(S1);Request(S3); …
  • P2: ···Relese(S2);Request(S1); ···
  • P3: ···Relese(S3);Request(S2); ···

并不可能发生死锁。但若改成下述的运行顺序

  • P1: ···Request(S3);Relese(S1);···
  • P2: ···Request(S1);Relese(S2); ···
  • P3: ···Request(S2);Relese(S3); ···

则可能发生死锁。

5)进程推进顺序不当引起死锁

由于进程在运行中具有异步性特征,这可能使P1和P2两个进程按下述两种顺序向前推进。

a) 进程推进顺序合法

当进程P1和P2并发执行时,如果按照下述顺序推进:P1:Request(R1); P1:Request(R2); P1: Relese(R1);P1: Relese(R2); P2:Request(R2); P2:Request(R1); P2: Relese(R2);P2: Relese(R1);这两个进程便可顺利完成,这种不会引起进程死锁的推进顺序是合法的。

b) 进程推进顺序非法

若P1保持了资源R1,P2保持了资源R2,系统处于不安全状态,因为这两个进程再向前推进,便可能发生死锁。例如,当P1运行到P1:Request(R2)时,将因R2已被P2占用而阻塞;当P2运行到P2:Request(R1)时,也将因R1已被P1占用而阻塞,于是发生进程死锁。

死锁产生的 4 个必要条件

虽然进程在运行过程中,可能发生死锁,但死锁的发生也必须具备一定的条件,死锁的发生必须具备以下四个必要条件

1)互斥条件
  • 指进程对所分配到的资源进行排它性使用,即在一段时间内某资源只由一个进程占用。如果此时还有其它进程请求资源,则请求者只能等待,直至占有资源的进程用毕释放。
2)请求和保持条件
  • 指进程已经保持至少一个资源,但又提出了新的资源请求,而该资源已被其它进程占有, 此时请求进程阻塞,但又对自己已获得的其它资源保持不放。
3)不可剥夺条件
  • 指进程已获得的资源,在未使用完之前,不能被剥夺,只能在使用完时由自己释放。
4)环路等待条件
  • 指在发生死锁时,必然存在一个进程——资源的环形链
  • 即进程集合{P0,P1,P2,···,Pn}中的P0正在等待一个P1占用的资源;P1正在等待P2占用的资源,……,Pn正在等待已被P0占用的资源。

3. 如何避免死锁,常见算法与原理

打破四个必要条件之一

理解了死锁的原因,尤其是产生死锁的四个必要条件,就可以最大可能地避免、预防和解除死锁。只要打破四个必要条件之一就能有效预防死锁的发生

  • 打破互斥条件:改造独占性资源为虚拟资源,大部分资源已无法改造。
  • 打破不可剥夺条件:当一进程占有一独占性资源后又申请一独占性资源而无法满足,则退出原占有的资源。
  • 打破请求和保持条件:采用资源预先分配策略,即进程运行前申请全部资源,满足则运行,不然就等待,这样就不会占有且申请。
  • 打破循环等待条件:实现资源有序分配策略,对所有设备实现分类编号,所有进程只能采用按序号递增的形式申请资源
两种算法
1) 有序资源分配法

这种算法按某种规则把系统中的所有资源统一编号(例如打印机为1、磁带机为2、磁盘为3、等等),申请时必须以升序申请
系统要求申请进程

  • 1、对它所必须使用的而且属于同一类的所有资源,必须一次申请完;
  • 2、在申请不同类资源时,必须按各类设备的编号依次申请。
    例如:进程PA,使用资源的顺序是R1,R2;
       进程PB,使用资源的顺序是R2,R1;
       若采用动态分配有可能形成环路条件,造成死锁
       
    采用有序资源分配法:R1的编号为1,R2的编号为2;
    PA:申请次序应是:R1,R2
    PB:申请次序应是:R1,R2
    这样就破坏了环路条件,避免了死锁的发生
2)银行家算法

我们可以把操作系统看作是银行家,操作系统管理的资源相当于银行家管理的资金,进程向操作系统请求分配资源相当于用户向银行家贷款。
为保证资金的安全,银行家规定:

  • (1) 当一个顾客对资金的最大需求量不超过银行家现有的资金时就可接纳该顾客;
  • (2) 顾客可以分期贷款,但贷款的总数不能超过最大需求量;
  • (3) 当银行家现有的资金不能满足顾客尚需的贷款数额时,对顾客的贷款可推迟支付,但总能使顾客在有限的时间里得到贷款;
  • (4) 当顾客得到所需的全部资金后,一定能在有限的时间里归还所有的资金。

操作系统按照银行家制定的规则为进程分配资源,当进程首次申请资源时,要测试该进程对资源的最大需求量,如果系统现存的资源可以满足它的最大需求量则按当前的申请量分配资源,否则就推迟分配。当进程在执行中继续申请资源时,先测试该进程本次申请的资源数是否超过了该资源所剩余的总量。若超过则拒绝分配资源,若能满足则按当前的申请量分配资源,否则也要推迟分配。

银行家算法框图

这里写图片描述

猜你喜欢

转载自blog.csdn.net/sinat_36629696/article/details/80077496