什么是死锁?
死锁是指在多进程或多线程的环境中,多个进程或线程相互等待对方释放资源,导致它们永远不能继续执行下去的状态。具体而言,死锁发生时,涉及的进程/线程持有一些资源,并且在等待其他进程/线程所持有的资源,而这些资源又被其他进程/线程等待。
死锁的四个必要条件
- 互斥条件(Mutual Exclusion):至少有一个资源必须处于非共享模式,即每次只能有一个进程/线程使用该资源。如果其他进程/线程请求该资源,请求者必须等待,直到资源被释放。
- 持有并等待条件(Hold and Wait):至少有一个进程/线程在持有一个资源的同时,正在等待其他被其他进程/线程占用的资源。
- 不剥夺条件(No Preemption):资源不能被强制剥夺,只能在进程/线程释放资源时才能被其他进程/线程获得。
- 循环等待条件(Circular Wait):存在一种进程/线程的循环链,其中每个进程/线程都在等待下一个进程/线程持有的资源。
避免死锁的方法
资源分配图法:
- 通过构建资源分配图,实时监控资源分配情况,避免进入死锁状态。通过控制进程/线程的资源请求,避免出现循环等待的情况。
银行家算法:
- 银行家算法是一种避免死锁的动态资源分配算法,通过对资源请求进行审查,确保在资源分配前不会导致系统进入死锁状态。
请求资源时一次性分配:
- 进程/线程在开始时一次性请求所需的所有资源,而不是分阶段请求,避免持有部分资源而等待其他资源导致死锁。
避免循环等待:
- 可以对资源进行排序,并强制要求进程/线程按照一定顺序申请资源。如果进程/线程无法按顺序申请资源,则进行阻塞和回退,防止死锁的发生。
采用抢占式资源管理:
- 当进程/线程等待的资源无法获取时,可以将已占用的资源抢占,暂时中断进程/线程的执行,重新安排资源,避免死锁。
资源排序法:
- 对所有资源类型进行排序,进程/线程只能按顺序申请资源。如果一个进程/线程申请某种资源,必须遵守资源的顺序,避免形成循环等待。
银行家算法
银行家算法(Banker’s Algorithm)是由埃德斯特朗(Edsger Dijkstra)提出的一种动态资源分配算法,用于避免死锁。它的核心思想是:在每次资源分配时,模拟假设当前资源分配后的系统状态是否安全,如果是安全的,才分配资源,否则不分配。
银行家算法的工作原理:
1.系统资源状态的安全性检查: 银行家算法假设系统当前处于一个安全状态。每当一个进程请求资源时,系统会模拟资源分配后的状态,检查是否会进入不安全状态。若不安全,则拒绝该请求,避免进入死锁状态。
2.资源分配的三大主要数据结构:
-
Available:系统中每种资源的剩余可用数量。
-
Max:每个进程对每种资源的最大需求。
-
Allocation:每个进程当前已分配到的资源数。
-
Need:每个进程对每种资源还需的资源数,即 Need[i] = Max[i] - Allocation[i]。
3.安全性算法:
- 判断当前状态是否安全,首先通过“安全序列”进行判断。如果能够在某一顺序下,按照进程的需求逐一分配资源,使得所有进程都能完成其执行,并且最终释放所有资源,说明系统是安全的;否则,系统就是不安全的。
银行家算法的步骤:
1.初始化:
- 系统初始化时,计算并记录每个进程的最大需求和当前分配资源。
2.请求资源:
- 当进程请求资源时,系统检查请求是否合理。如果请求资源超过了进程的最大需求,或者请求超过了系统的可用资源,则直接拒绝请求。
3.安全性检查:
- 如果请求资源后,系统仍然处于安全状态(即可以找到一个执行序列,使得所有进程都能完成),则分配资源;否则,回滚请求。
举个例子:
假设有以下系统资源和进程的需求情况:
资源可用情况表
资源类型 | 可用资源 |
---|---|
A | 3 |
B | 3 |
C | 2 |
进程需求情况表
进程 | 最大需求 | 当前分配 | 需要资源 |
---|---|---|---|
P0 | (3, 2, 2) | (2, 1, 1) | (1, 1, 1) |
P1 | (2, 1, 1) | (1, 0, 0) | (1, 1, 1) |
P2 | (3, 3, 2) | (2, 1, 1) | (1, 2, 1) |
在这种情况下,系统会在分配资源之前,检查是否存在安全的执行序列。如果资源分配可能导致死锁,银行家算法就会拒绝该请求。
总结
- 死锁是指多个进程或线程相互等待,无法继续执行。
- 避免死锁的方法包括资源分配图、银行家算法、一次性分配资源、避免循环等待等。
- 银行家算法通过检查资源请求后的系统状态是否安全来避免死锁,它模拟资源分配后的情况,确保系统始终处于安全状态。