文章目录
- 91、为什么会产生死锁?
- 什么是死锁?
- 死锁产生的四个必要条件
- 信号量机制中的死锁原因
- 示例:可能导致死锁的信号量使用
- 如何避免死锁
- 在之前的信号量问题中如何避免死锁【2011年408真题】
- 银行系统示例
- 缓冲区问题示例
- 具体示例:避免死锁的代码设计
- 顾客进程 \( P_{\text{customer}} \)
- 营业员进程 \( P_{\text{teller}} \)
- 结论
- 92、产生死锁有什么条件?
- 死锁产生的条件
- 1. 互斥条件(Mutual Exclusion)
- 2. 占有且等待条件(Hold and Wait)
- 3. 不剥夺条件(No Preemption)
- 4. 循环等待条件(Circular Wait)
- 死锁的产生过程示例
- 如何避免死锁
- 在信号量机制中避免死锁
- 结论
- 93、有什么办法可以解决死锁问题?
- 1. **死锁预防(Deadlock Prevention)**
- (1)破坏互斥条件:
- (2)破坏占有并等待条件:
- (3)破坏不剥夺条件:
- (4)破坏循环等待条件:
- 2. **死锁避免(Deadlock Avoidance)**
- 银行家算法(Banker's Algorithm):
- 3. **死锁检测与恢复(Deadlock Detection and Recovery)**
- (1)死锁检测:
- (2)死锁恢复:
- 4. **组合方法**
- 实际应用中的策略
- 总结:
- 94、什么是死锁避免的银行家算法?
- 银行家算法原理
- 核心概念:
- 银行家算法使用的几个数据结构:
- 银行家算法的步骤
- 银行家算法的例子
- 初始状态:
- **系统当前可用资源**:
- **某进程请求资源示例:P1请求(1, 0, 2)**资源。
- 步骤 1:检查资源请求是否合法
- 步骤 2:尝试分配资源
- 步骤 3:检查系统是否安全
- 步骤 4:分配资源
- 总结
- 95、实现临界区互斥机制必须遵循的准则是?
- 临界区互斥机制的四个准则
- 解释每个准则的目的
- 实现互斥机制的常见方法
- 总结
91、为什么会产生死锁?
什么是死锁?
死锁(Deadlock) 是指两个或多个进程在执行过程中,因为争夺资源而造成一种互相等待的现象,使得这些进程无法继续执行下去。简单来说,死锁就像是两个司机在狭窄的路口相向而行,互相让路却都不愿意后退,导致双方都无法移动。
死锁产生的四个必要条件
根据经典的死锁理论,死锁的产生需要同时满足以下四个条件:
-
互斥条件(Mutual Exclusion):
- 至少有一个资源必须处于非共享模式,即一次只能被一个进程使用。
-
占有且等待条件(Hold and Wait):
- 一个进程至少已经占有了一个资源,并且正在等待获取被其他进程占有的资源。
-
不剥夺条件(No Preemption):
- 已经分配给一个进程的资源,不能被其他进程强行剥夺,只有在该进程完成任务后才能释放资源。
-
循环等待条件(Circular Wait):
- 存在一个进程环,每个进程都持有下一个进程所需要的资源,形成一个循环等待的链条。
信号量机制中的死锁原因
在使用信号量(Semaphore)进行进程同步与互斥时,如果不谨慎设计,可能会触发上述死锁条件。以下是一些常见的死锁原因:
-
不一致的信号量获取顺序:
- 当多个进程以不同的顺序请求多个信号量时,容易形成循环等待。例如,进程A先请求信号量S1,再请求信号量S2;而进程B先请求信号量S2,再请求信号量S1,这样就可能导致死锁。
-
忘记释放信号量:
- 如果一个进程在持有信号量后由于异常或错误未能释放信号量,其他进程将永远等待该信号量,导致系统进入死锁状态。
-
信号量初始值设置不当:
- 如果信号量的初始值设置不正确,可能导致某些进程无法获取到所需的资源,从而陷入无限等待。
示例:可能导致死锁的信号量使用
考虑以下两个信号量 S1
和 S2
,以及两个进程 P1
和 P2
:
// 进程 P1
P(S1);
P(S2);
// 临界区
V(S2);
V(S1);// 进程 P2
P(S2);
P(S1);
// 临界区
V(S1);
V(S2);
死锁情景:
- 进程
P1
先获取S1
,然后尝试获取S2
。 - 同时,进程
P2
先获取S2
,然后尝试获取S1
。 - 这样,
P1
持有S1
并等待S2
,而P2
持有S2
并等待S1
,形成循环等待,导致死锁。
如何避免死锁
为了防止死锁的发生,可以采取以下策略:
-
破坏死锁的四个必要条件之一:
- 避免占有且等待:要求进程在请求资源时,必须一次性请求所需的所有资源,如果无法全部获取,则释放已获取的资源并重试。
- 资源有序分配:为所有资源分配一个全局顺序,所有进程按照相同的顺序请求资源,避免循环等待。
- 允许资源被剥夺:如果一个进程等待获取资源超时,系统可以强制剥夺该进程已持有的资源。
-
确保信号量获取的顺序一致:
- 设计所有进程按照相同的顺序请求多个信号量,避免不同进程以不同的顺序请求资源,防止循环等待。
-
正确释放信号量:
- 确保每个获取操作(
P
)都有对应的释放操作(V
),即使在异常情况下也能正确释放,避免信号量永久被占用。
- 确保每个获取操作(
在之前的信号量问题中如何避免死锁【2011年408真题】
让我们回顾一下之前银行系统和缓冲区问题的信号量设计,并说明如何避免死锁。
银行系统示例
在银行系统中,我们定义了以下信号量:
mutex_ticket
:保护取号机的互斥访问,初始值为1。seats
:表示等待座位的空闲数量,初始值为10。waiting
:表示有多少位顾客在等待被叫号,初始值为0。service
:用于让营业员通知一位顾客开始接受服务,初始值为0。
死锁避免措施:
-
一致的信号量获取顺序:
- 顾客在进入等待区时,首先执行
P(seats)
,然后执行P(mutex_ticket)
。 - 营业员在叫号时,首先执行
P(waiting)
,然后执行V(service)
。
由于顾客和营业员获取信号量的顺序不冲突(顾客主要涉及
seats
和mutex_ticket
,营业员涉及waiting
和service
),不会形成循环等待。 - 顾客在进入等待区时,首先执行
-
确保信号量的正确释放:
- 每个
P
操作后都有对应的V
操作,确保信号量不会被永久占用。
- 每个
缓冲区问题示例
在缓冲区问题中,我们定义了以下信号量:
mutex
:保护缓冲区的互斥访问,初始值为1。empty
:表示缓冲区中的空位数量,初始值为N。odd_count
:表示缓冲区中的奇数数量,初始值为0。even_count
:表示缓冲区中的偶数数量,初始值为0。
死锁避免措施:
-
一致的信号量获取顺序:
- 生产者
P1
首先执行P(empty)
,然后执行P(mutex)
。 - 消费者
P2
(处理奇数)和P3
(处理偶数)分别执行P(odd_count)
或P(even_count)
,然后执行P(mutex)
。
由于所有进程在获取互斥信号量
mutex
时,已经通过其他信号量(如empty
,odd_count
,even_count
)确保缓冲区的状态,一致的获取顺序避免了循环等待。 - 生产者
-
确保信号量的正确释放:
- 每个
P(mutex)
操作后都有对应的V(mutex)
操作,确保缓冲区的互斥访问能够被释放。 - 生产者和消费者在完成操作后,适时释放
empty
,odd_count
,even_count
信号量,避免资源被永久占用。
- 每个
具体示例:避免死锁的代码设计
以银行系统为例,确保死锁不会发生的代码设计如下: