[日报] 死锁的必要条件

本文详细阐述了死锁的概念、产生的原因、各种死锁模型(如One-ResourceModel、ANDModel等)、死锁的解决方法(预防、避免和检测恢复)以及相关概念如活锁、饥饿和无锁。

目录

一、什么是死锁

二、死锁产生的原因

三、死锁模型

1.One-Resource Model

2.AND Model

3.OR Model

4.AND-OR Model

5.Unrestricted Model

四、死锁的解决方法

1.死锁预防

2.死锁避免

3.死锁检测和恢复

五、其他碎知识补充

1.活锁

2.饥饿

3.混乱

4.无锁


一、什么是死锁

死锁是指两个或多个进程在执行过程中,因为争夺资源或者相互等待而导致的一种僵持状态,如果没有外部干预,它们都无法继续运行。

例如,一个进程 p1占用了显示器,同时又必须使用打印机,而打印机被进程p2占用,p2又必须使用显示器,这样就形成了死锁。 因为p1必须等待p2发布打印机才能够完成工作并发布屏幕,同时p2也必须等待p1发布显示器才能完成工作并发布打印机,形成循环等待的死锁。

二、死锁产生的原因

如果系统中只有一个进程,当然不会产生死锁。如果每个进程仅需求一种系统资源,也不会产生死锁。不过这只是理想状态,在现实中是可遇不可求的。

死锁的必要条件是指在一个系统中,如果要发生死锁,必须同时满足的四个条件 。这四个条件分别是:

  • 互斥条件:每个资源要么已经分配给一个进程,要么就是可用的,不能同时被多个进程共享。
  • 占有和等待条件:已经得到了某些资源的进程可以再请求新的资源,而不必释放已经占有的资源。
  • 不可抢占条件:已经分配给一个进程的资源不能被其他进程强行夺走,只能由占有该资源的进程自愿释放。
  • 环路等待条件:存在一个进程等待队列,其中每个进程都在等待下一个进程所占有的资源,形成一个环路。

这些条件是死锁的必要条件,但不一定是充分条件,也就是说即使这些条件都满足了,也不一定会发生死锁,因为可能存在某种调度策略可以避免死锁的发生。如果要预防或解除死锁,就必须破坏至少一个条件。

三、死锁模型

死锁的模型是指对死锁的产生条件和形式的抽象描述。不同的模型对死锁的检测和解决方法有不同的影响。根据对并发系统中请求的限制程度的不同,死锁共有以下几种模型:

1.One-Resource Model

这是最简单的死锁模型,它假设每个事务每次最多发出一个资源请求,也就是说它的等待图的中每个节点的出度最大为1。事务阻塞直到它发出的请求得到响应。因此这种模型的死锁检测就是查找等待图中是否有环存在。

2.AND Model

与One-Resource 不同的是,这种模型假设每个事务可能同时发出多个请求,这个事务阻塞直到它一次发出的多个请求都得到响应。也就是说,它允许等待图的每个节点的出度为 [0, n]。这种模型的死锁检测和One-Resource一样也是确认等待图中是否有环存在,但不同的是,因为允许一个节点的出度大于1,所以一个事务可能同时参与到了多个环中,它要等到所有的环都被破坏才能解除死锁。

3.OR Model

它是在AND Model上进一步放宽条件,也就是说一个事务可能同时发出一个或多个请求,但是只要有一个请求得到响应,事务即可继续推进。因此这种模型的死锁检测又和上面一种不同,在等待图中,一个节点还是允许有 [0, n]个出度,也就是说这个事务可能参与到了多个环中,只有当这个节点的所有出度所在的路径都在环中时,这个事务才进入死锁,只要有一条路径存在终点,那么这个事务就没有被死锁。

4.AND-OR Model

这是AND Model和OR Model的一种组合模型,它允许一个事务发出 [0, n]个请求,这些请求中即包括AND模型请求,也包括OR模型请求。这样死锁检测更加复杂,甚至没有一个熟悉的图论模型与之对应。对这个模型来说,最容易想到的死锁检测方式,就是反复应用OR 模型的死锁检测方式进行死锁检测。因为死锁具有稳定性,虽然AND—OR进入死锁之前的状态检查十分复杂,但是只要它进入死锁,那么它的状态就不会改变。也就是说当它形成死锁后,它的检测结果和OR模型是一样的,即各个出度都处与环中。

5.Unrestricted Model

这种模型是最通用的模型,它不限制事务的资源请求规则,由于十分复杂,在此也不做介绍。

四、死锁的解决方法

死锁的解决方法主要有以下三种:

1.死锁预防

在程序运行之前,通过破坏死锁的必要条件之一,来阻止死锁的发生。例如规定进程按照一定的顺序请求资源,或者限制进程在申请新资源时必须释放已有资源。

死锁的检测方法主要有资源分配图法和时间延迟法。资源分配图法通过构建进程-资源分配图来检测是否存在环路,时间延迟法通过设置超时时间来检测进程是否进入死锁状态。

2.死锁避免

在程序运行时,通过动态地分析资源的分配情况,来避免进入不安全的状态。例如使用银行家算法,根据进程的最大需求和系统的可用资源,判断是否可以安全地分配资源。

3.死锁检测和恢复

在程序运行时,不试图阻止死锁,而是当检测到死锁发生时,采取措施进行恢复。例如使用死锁检测算法,根据进程-资源分配图,判断是否存在环路,如果存在,则说明发生了死锁。然后,可以通过剥夺或终止一些进程,来释放资源,从而解除死锁。


死锁的出现场景主要有操作系统进程调度、数据库事务处理、分布式系统资源分配等。如操作系统中进程对共享资源如内存、磁盘等的竞争可能导致死锁。

五、其他碎知识补充

1.活锁

活锁(livelock),与死锁相似,死锁是行程都在等待对方先释放资源;活锁则是行程彼此释放资源又同时占用对方释放的资源。当此情况持续发生时,尽管资源的状态不断改变,但每个行程都无法获取所需资源,使得事情没有任何进展。

2.饥饿

饥饿(starvation),是指某些进程因为优先级低或者等待条件不满足,而长期得不到所需的资源,无法执行。饥饿可能是由于资源分配不公平或者调度算法不合理造成的。饥饿的解决方法是保证每个进程都能获得一定的服务,例如使用老化技术,让进程的优先级随着等待时间的增加而提高。

3.混乱

混乱,多个进程由于资源竞争和优先级问题而处于混乱状态。

4.无锁

无锁(lock-free),是指一种不使用互斥锁或者信号量等同步机制,而是通过原子操作来实现多线程之间的协作的编程方法。无锁的优点是可以避免死锁、活锁、饥饿等问题,提高并发性能和可扩展性。无锁的缺点是编程难度高,需要考虑更多的细节和边界情况。无锁的常用技术有CAS(比较并交换)、ABA问题和解决方案、无锁数据结构等。

### 死锁的四个必要条件 死锁是并发编程中的常见问题,通常发生在多个线程或进程之间互相等待对方持有的资源,导致系统永久阻塞。以下是死锁产生的四个必要条件: #### 1. 互斥(Mutual Exclusion) 资源不能被共享,只能由一个进程使用。这意味着某些资源在任何时刻只能被一个进程独占性地访问[^1]。 #### 2. 占有且等待(Hold and Wait) 一个进程应占有至少一个资源,并同时等待另一个资源,而该资源为其他进程所占有。这种情况下,进程既持有资源又请求新的资源[^2]。 #### 3. 不剥夺(No Preemption) 已经分配的资源不能从相应的进程中被强制地剥夺。只有当占有资源的进程主动释放资源时,其他进程才能获得该资源[^2]。 #### 4. 循环等待(Circular Wait) 系统中若干进程组成环路,该环路中每个进程都在等待相邻进程正占用的资源。这形成了一种循环依赖关系,进一步加剧了死锁的发生可能性。 ### 解决死锁的方法 解决死锁的方法主要包括以下几种: #### 1. 预防死锁 通过破坏死锁的四个必要条件之一来预防死锁的发生。例如: - **破坏互斥条件**:尽可能将资源设计为可共享的形式。 - **破坏占有且等待条件**:要求进程在开始执行前一次性申请所有需要的资源。 - **破坏不剥夺条件**:允许系统强行剥夺进程已占有的资源。 - **破坏循环等待条件**:对资源进行全局编号,要求进程按序号顺序申请资源[^2]。 #### 2. 避免死锁 通过资源分配算法动态地避免死锁的发生。银行家算法是一种典型的避免死锁的算法,它通过模拟分配过程判断是否会导致死锁,从而决定是否分配资源[^2]。 #### 3. 检测与恢复 允许死锁发生,但通过检测机制发现死锁并采取措施恢复系统。常见的恢复方法包括终止一个或多个陷入死锁的进程、剥夺某些进程的资源等。 ```python # 示例:简单的死锁检测算法 def detect_deadlock(processes, resources): allocation = [[0, 1, 0], [2, 0, 0], [0, 0, 1]] # 当前资源分配矩阵 request = [[0, 0, 1], [1, 0, 0], [0, 1, 0]] # 进程资源请求矩阵 available = [1, 1, 1] # 系统可用资源向量 work = available.copy() finish = [False] * len(processes) while False in finish: found = False for i in range(len(processes)): if not finish[i] and all([work[j] >= request[i][j] for j in range(len(resources))]): work = [work[j] + allocation[i][j] for j in range(len(resources))] finish[i] = True found = True if not found: return "Deadlock detected!" return "No deadlock detected!" print(detect_deadlock(["P1", "P2", "P3"], ["R1", "R2", "R3"])) ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值