目录
一、分类
二、预防死锁
1、破坏互斥条件
2、破坏不剥夺条件
3、破坏请求和保持条件
4、破坏循环等待条件
5、总结
三、避免死锁
1、什么是安全序列
2、安全状态和不安全状态
3、银行家算法
(1)核心思想
(2)例子
(3)代码实现
(4)考点
四、死锁的检测和解除
1、死锁的检测
(1)资源分配图
(2)例子
2、死锁的解除
五、总结
一、分类
二、预防死锁
1、破坏互斥条件
2、破坏不剥夺条件
3、破坏请求和保持条件
4、破坏循环等待条件
5、总结
三、避免死锁
1、什么是安全序列
- 所谓安全序列,就是指如果系统按照这种序列分配资源,则每个进程都能顺利完成。
- 只要能找出一个安全序列,系统就是安全状态。
- 当然,安全序列可能有多个。
2、安全状态和不安全状态
- 如果分配了资源之后,系统中找不出任何一个安全序列,系统就进入了不安全状态。
- 这就意味着之后可能所有进程都无法顺利的执行下去。
- 当然,如果有进程提前归还了一些资源,那系统也有可能重新回到安全状态,不过我们在分配资源之前总是要考虑到最坏的情况。
- 如果系统处于安全状态,就一定不会发生死锁。
- 如果系统进入不安全状态,就可能发生死锁(处于不安全状态未必就是发生了死锁,但发生死锁时一定是在不安全状态)
3、银行家算法
(1)核心思想
在进程提出资源申请时,先预判此次分配是否会导致系统进入不安全状态。如果会进入不安全状态,就暂时不答应这次请求,让该进程先阻塞等待。
(2)例子
1、若我们有如下例子,我们计算出各个进程最大还需要多少,和剩余多少
2、我们依次对比各个进程需要的资源和剩余资源
此时P1一定可以顺利执行完毕,所以将P1存入安全序列,并增加可用资源的值
此时的安全序列为:P1
3、然后重新从P0开始比对,发现还是不够;接下来是P2,同样不够;
直到P3,剩余资源满足P3的要求资源
此时的安全序列为:P1、P3
4、依此类推最终得到的安全序列为:P1、P3、P0、P2、P4
(3)代码实现
#include <iostream>
#include <vector>
using namespace std;
// 定义函数:银行家算法
bool banker_algorithm(vector<int> &available, vector<vector<int>> &max_request, vector<vector<int>> &allocation)
{
// 计算出需要的资源和已分配的资源
vector<vector<int>> need(max_request.size(), vector<int>(max_request[0].size()));
for (int i = 0; i < allocation.size(); i++) {
for (int j = 0; j < allocation[0].size(); j++) {
need[i][j] = max_request[i][j] - allocation[i][j];
}
}
// 定义一些变量
vector<bool> finish(allocation.size(), false); // 用于标记每个进程是否完成
vector<int> work(available); // 定义工作向量
// 实现银行家算法
while (true) {
// 在未完成的进程中查找一个满足条件的进程
int i = -1;
for (int k = 0; k < allocation.size(); k++) {
if (!finish[k]) {
bool can_allocated = true;
for (int j = 0; j < allocation[0].size(); j++) {
if (need[k][j] > work[j]) {
can_allocated = false;
break;
}
}
if (can_allocated) {
i = k;
break;
}
}
}
// 如果找不到满足条件的进程,则返回false表示不能进行资源分配
if (i == -1) {
return false;
}
// 更新工作向量和已完成的进程
for (int j = 0; j < allocation[0].size(); j++) {
work[j] += allocation[i][j];
}
finish[i] = true;
// 如果所有进程都已完成,则返回true表示可以进行资源分配
if (count(finish.begin(), finish.end(), true) == finish.size()) {
return true;
}
}
}
int main()
{
// 测试
vector<int> available = {3, 3, 2};
vector<vector<int>> max_request = {
{7, 5, 3},
{3, 2, 2},
{9, 0, 2},
{2, 2, 2},
{4, 3, 3},
};
vector<vector<int>> allocation = {
{0, 1, 0},
{2, 0, 0},
{3, 0, 2},
{2, 1, 1},
{0, 0, 2},
};
if (banker_algorithm(available, max_request, allocation)) {
cout << "可以进行资源分配" << endl;
} else {
cout << "不能进行资源分配" << endl;
}
return 0;
}
(4)考点
四、死锁的检测和解除
1、死锁的检测
(1)资源分配图
(2)例子
1、我们有如下例子
2、我们观察P1连接的线,发现它在请求R2的一个资源;而R2此时恰好剩余一个资源,所以P1可以不会发生阻塞;而P2申请的R1资源已经被分配完了,所以P2会被阻塞。
3、当P1释放资源后,P2被唤醒,此时它也可以正常运行
4、当消除所有边后