进程死锁

本文深入探讨了死锁的定义、成因、检测、预防和解决方法,包括使用有向图描述死锁,阐述了银行家算法,并提供了死锁检测的实例,帮助读者全面了解如何应对这一操作系统中的常见问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

死锁描述

    用有向图来描述这种死锁。在这种有向图中,圆圈表示进程,方形表示资源。资源节点到进程节点的边表示该资源被进程占用,由进程指向资源节点的有向边表示进程申请该资源。

     如果形成了如图C所以的环表示死锁了。



死锁条件

1、互斥条件

      指进程对所分配到的资源进行排它性使用,即在一段时间内某资源只由一个进程占用。如果此时还有其它进程请求资源,则请求者只能等待,直至占有资源的进程用毕释放。

2、请求和保持条件

    指进程已经保持至少一个资源,但又提出了新的资源请求,而该资源已被其它进程占有,此时请求进程阻塞,但又对自己已获得的其它资源保持不放。

3、不可抢占条件

    指进程已获得的资源,在未使用完之前,不能被剥夺,只能在使用完时由自己释放。

4、循环等待条件

    进程申请的资源被另一个进程占有,而另一个进程申请的资源被当前进程占有。如上图所示的环形。


死锁忽略

     鸵鸟算法,遇到死锁当没发生一样。


死锁恢复

    系统检测到死锁时,需要从死锁中恢复。一下两种处理方法。

1、挂起/恢复进程

      先将死锁环路中某进程挂起,等死锁环中某进程执行完后,某进程资源被回收后,再将被挂起的进程恢复执行。缺点:想象下这么个情景,如果某个进程写磁带写到一半,被你挂起了,多痛苦。所以选择挂起谁很纠结。

2、杀死进程

      杀死环中一个进程或多个进程。杀死一个进程检测系统状态,如果还是没达到要求,继续杀死第二个进程。但是检测系统状态本身开销就很大,所以此方法也不妙。

死锁检测

    根据画的这种资源分配图,得到检测方法。

1、单种资源类型下的死锁检测

      直接上例子:假设一个系统由A到G七个进程,R到W六中资源,资源关系如下:

(1)A拥有R资源,需要S资源

(2)B需要T资源

(3)C需要S资源

(4)D拥有U资源,需要S、T资源

(5)E拥有T资源,需要V资源

(6)F拥有W资源,需要S资源

(7)G拥有V资源,需要U资源

则根据上面的资源关系,可以画出下面的资源图:


      直观的看出:上图形成了一个环形,表示会造成死锁。这种方案编程根据有向图的深度优先搜索,判断有向图中是否形成了环形。

2、多种资源类型下的死锁检测

      还是直接上例子:


      C矩阵的三行分别对应三个进程P0、P1和P2已经分配的资源,右边表示还需要的资源。由于系统剩下的资源A=[2 1 0 0],所以P2进程是可以完成的,于是分配给P2进程;P2完成后系统剩下的资源A=[4 2 2 0],再分配给P1;最后给P0,系统所有进程都能完成,则没有死锁。(跟银行家算法检测安全状态是一样的


死锁预防

    破坏死锁的四个条件:

1、破坏互斥条件

     不切实际,有些资源就必须实现互斥访问。例如打印机。

2、破坏请求和保持条件

      要求进程一开始声明就期望获得它的全部资源,操作系统会检测进程所需的资源是否全部可用,只有可用的时候进程才执行。如果不是进程放弃目前拥有的资源。

      缺点:进程放弃资源后,也许会有些长的进程长时间占有资源,这样导致系统反应慢。想象一下打印机用到一半被别人抢过去的感觉。

3、破坏不可抢占条件

      允许当前进程拥有的资源可以被其他进程抢过去。还是上面一个缺点,用到一半的磁带机被别人抢过去了。

4、破坏循环等待条件

      强制每个进程只能拥有一种资源。进程要想申请资源,必须释放手上目前拥有的资源。实现该方案就是该资源标号,规定进程必须按照资源编号从前往后申请。(进程一开始就获取全部资源的情况不存在


       这样进程如果需要磁带机和打印机,那进程必须先申请磁带机,再申请打印机。这样大家的申请顺序就不会乱。


死锁避免

      预防死锁正如上面所说,存在着某些困难。操作系统采用一种折中方案,以避免死锁发生,也就是牛逼的银行家算法。直接上例子比较好:


     上面有P0、P1、P2、P3四个进程,左边的表格表示已经分配的资源,右边的表格是仍需要的资源。操作系统系统包含的资源5个磁带机、4个打印机和3个绘图仪。将矩阵A中纵向相加表示已经分配给进程总的资源为4个磁带,3个打印机和2个绘图仪,剩下1个磁带机、1个打印机和1个绘图仪。

       如果存在一个由系统中所有进程构成的安全序列P1,…,Pn,则系统处于安全状态。安全状态一定是没有死锁发生。反之如果不存在安全状态,则有死锁发生。

     银行家算法:用当前剩下的资源(1、1、1)去扫描右边的表格,如果这几个进程中,没有一个进程能够利用剩下的资源完成,则系统处于不安全状态。表示有可能发生死锁。如果有几个进程能够利用剩下的资源完成,则将资源分配给某个进程,待进程运行完,把资源还给系统,再继续寻找。如果寻找过程中出现了不安全状态,就不能按照这种方案分配。

      实现:定义系统拥有资源数组Avaliable,进程已经分配资源矩阵Alloc,进程需要资源矩阵Max,Max-Alloc得到需求矩阵Need。每轮都要扫描需求矩阵。

     上面的例子:

    (1)系统剩下的资源1、1、1,看矩阵B,就这点资源可以保证P0、P1、P3中任何一个进程完成,所以认为系统暂时处于安全状态;。

    (2)选择P1,将剩下资源分配给P1,这样P1完成后还回资源,则剩下的资源变为:120+001=121;

    (3)P0、P3都可以完成,选P3,P3完成后,剩下的资源变为:212+010=222;

    (4)P0、P2都满足,选择P1,则P0完成后,剩下的资源变为:300+122=422;

    (5)选择P2,最终所有进程能够完成运行。

注:在每轮扫描过程中,如果没有进程可以完成运行,则表示出现了不安全状态,则不能分配内存。

### 线程死锁进程死锁的区别与联系 #### 概念定义 线程死锁是指在同一进程中,两个或多个线程互相持有对方所需的资源并等待对方释放资源的情况[^1]。这种情况下,涉及的线程会陷入永久阻塞状态。 进程死锁则是指不同进程之间由于竞争有限资源而导致的一种僵局状态,其中每个进程都持有一些资源并等待其他进程持有的资源被释放[^4]。 两者的核心区别在于作用范围的不同:线程死锁发生在单个进程内部,而进程死锁则跨越不同的进程边界。 --- #### 死锁的原因分析 无论是线程还是进程死锁,其形成的根本原因是满足了四个必要条件——互斥条件、请求保持条件、不可剥夺条件和循环等待条件[^3]: - **互斥条件**:某些资源一次只能由一个实体(线程/进程)占用。 - **请求保持条件**:已占有部分资源的实体进一步申请新的资源,如果申请不到,则进入等待状态,但仍保留原有资源。 - **不可剥夺条件**:只有拥有者主动释放资源才能改变该资源的状态。 - **循环等待条件**:存在一组线程或者进程{P0, P1, ..., Pn},其中Pi正在等待P(i+1)%n所占有的资源。 具体到实现层面: - 对于线程死锁,常见原因是一个线程获取了一把锁之后再去尝试获取另一把锁,但由于后者已被其他线程锁定从而引发死锁。 - 而对于进程死锁,除了上述提到的竞争共享资源外,还可能因为通信机制设计不合理引起,比如两方都在等待对方发送消息。 --- #### 解决方案探讨 针对线程死锁进程死锁,有多种通用策略用于预防和解除这些问题: ##### 预防措施 1. **破坏请求保持条件** 可通过一次性分配所有所需资源避免中间再次请求新资源的行为。例如,在数据库事务处理中采用这种方式减少潜在冲突点[^2]。 2. **破坏顺序依赖性** 给定一系列资源按照固定全局序号访问能够有效防止出现环路结构。即规定任何线程或进程必须先按编号从小到大依次取得各资源实例[^5]。 3. **超时重试机制** 设计合理的超时时间窗口,一旦发现长时间未能成功获得目标资源,则自动放弃当前操作重新排队尝试。 ##### 处理手段 当已经发生了死锁现象后,可采取如下补救办法之一: - **强制终止某个参与者** 让其中一个受影响较大的线程或进程退出运行,并通知其余成员恢复正常工作流程。 - **调整优先级等级** 如果允许动态修改线程级别的话,可以让低级别的个体先行撤退以成全高级别的完成任务需求。 以下是基于Java语言的一个简单示例演示如何利用try-finally语句块确保及时解锁以防止单纯嵌套调用造成的隐患风险: ```java public class DeadlockAvoidanceExample { private final Object lockA = new Object(); private final Object lockB = new Object(); public void methodOne() { synchronized (lockA) { System.out.println("Thread 1: Holding lock A..."); try { Thread.sleep(10); } catch (InterruptedException e) {} synchronized (lockB) { System.out.println("Thread 1: Holding both locks!"); } } } public void methodTwo() { synchronized (lockB) { System.out.println("Thread 2: Holding lock B..."); try { Thread.sleep(10); } catch (InterruptedException e) {} synchronized (lockA) { System.out.println("Thread 2: Holding both locks!"); } } } } ``` 尽管此代码片段展示了两种方法分别加锁的过程,但如果严格按照预定次序执行就不会触发真正的死锁状况。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值