《操作系统》银行家算法c++代码实现
前言:
看了一篇博客,感觉算法实现的意思跟我想的不一样,又不想继续看别的代码了。索性就自己写了一个我所理解的,供大家参考
这里不介绍银行家算法的概念,重点放在代码实现上
想要看银行家算法的前置知识和概念可以看(复制进入)https://www.cnblogs.com/wkfvawl/p/11929508.html
- 说说我的算法的效果:
- 输入一系列进程对于资源的申请,如果不合法(申请的比需要的多),忽略
- 如果合法且目前能分配,那么尝试分配,然后安全性检查。如果安全就分配,否则取消分配
- 如果合法但目前不能分配,就先留着,以后再看看能不能分配
- 来一个资源申请就处理一个,而不是收到所有申请之后再依次处理。换句话说,处理第i个资源申请的时候,我们不会考虑i后面还未收到的资源申请
如果你想实现的效果和我的一样,那么可以继续看下去
- 由系统安全的定义可知,只要存在一个安全序列,那么系统就是安全的,因此我们只需找到一个安全序列就好
- 因此就像深度优先找出迷宫出口一样,我的算法借鉴DFS的思想,递归实现
- 我的不一定对,只是通过了老师给的用例,我自己在老师的用例上改进的用例以及<操作系统>罗宇书上的算法用例,就算错了能给大家一点启发也是不错的~(实际上自从发布之后,这篇随笔改了至少七八次,怕误导别人hh
- 我们的实验要求是输出安全序列,输出稍微改改就行,核心一样
输入用例格式
以下是老师给的输入用例
5 3
10 5 7
0 0 1 0 7 5 3
1 2 0 0 3 2 2
2 3 0 2 9 0 2
3 2 1 1 2 2 2
4 0 0 2 4 3 3
1 1 0 2
4 3 3 0
0 0 2 0
以下是我的改进输入用例
5 3
10 5 7
0 0 1 0 7 5 3
1 2 0 0 15 2 2
2 3 0 2 9 0 2
3 2 1 1 2 2 2
4 5 0 2 8 3 3
1 13 0 2
4 3 3 1
0 0 2 0
以下是课本上给出的用例(要测试的话,代码里的num记得改
5 3
10 5 7
0 0 0 0 9 0 0
1 0 0 0 8 0 0
2 0 0 0 0 0 0
3 0 0 0 0 0 0
4 0 0 0 3 0 0
1 4 0 0
4 2 0 0
0 2 0 0
4 1 0 0
1 4 0 0
0 7 0 0
代码解释
- 最开始我还在想,为什么安全检查函数书上要求多设work和finish数组,现在看来是很有必要的。
- 用work代替available,就是在available的副本上模拟尝试分配,不安全的话可以随时退出安全检查函数,反正不影响available数组,方便。直接在available改的话,要是尝试分配失败了,还要把数组恢复回来。函数里needed,finished,allocationed一样的道理
- finish保存目前还有哪些进程没有在安全序列,我们需要将资源尝试分配给不在安全序列里的进程。从输入中可以看到,不是所有进程都申请了资源的,因此可以让没申请资源的进程一直待在安全序列里,这样就不用管他们了
- 我就实现了两个函数,show用于展示当前系统资源,进程所占资源,进程还需要的资源之类的信息,方便调试,这个不用管;test函数用于检查满足进程i的需求后系统是否安全
以下是实现代码
#include<iostream>
using namespace std;
int n, m;//进程数和资源数
int available[10];//available[j]=k,表示系统有k个j类资源
int Max[10][10];//max[i][j]=k,表示进程i最多申请k个j类资源
int allocation[10][10];//allocation[i][j]=k,表示进程i已有k个j类资源
int need[10][10];//need[i][j]=k,表示i进程还需要k个j类资源
int request[10][10];//requst[i][j]=k,表示进程i正在申请k个j类资源
int finish[10];//finish[i]=1,表示进程i已经在安全队列中
void show()//方便调试写的,不过显示的是available而不是work,不能直接调用
{
cout << "\t\tallocation\t\tneed\t\tmax\t\tavailable" << endl;
for (int i = 0; i < n; i++)
{
cout << "进程" << i << "\t\t";
for (int j = 0; j < m; j++)
cout << allocation[i][j] << " ";
cout << "\t\t\t";
for (int j = 0; j < m; j++)
cout << need[i][j] << " ";
cout << "\t\t";
for (int j = 0; j < m; j++)
cout << Max[i][j] << " ";
cout << "\t\t";
for (int j = 0; j < m; j++)
cout << available[j]<<" ";
cout << endl;
}
}
int test(int availabled[],int finisheded[],int neededed[10][10],int allocationeded[10][10],int i)//满足进程i的请求,检查所有进程是否在安全队列,都在返回1,否则返回0
{
int finished[10],worked[10],needed[10][10],allocationed[10][10];//为了不改变finish,available和need,那我用复制品
for (int a = 0; a < 10; a++)
{
finished[a] = finisheded[a];
worked[a] = availabled[a];
for (int id = 0; id < 10; id++)
{
needed[id][a] = neededed[id][a];
allocationed[id][a] = allocationeded[id][a];
}
}
//模拟一下满足
int release = 1;
for (int a = 0; a < m; a++)
{
worked[a] -= request[i][a];
needed[i][a] -= request[i][a];
allocationed[i][a] += request[i][a];
if (worked[a] < 0)return 0;//因为函数内部进入递归时没有判断条件,所以这里需要判断,资源不够了,不能分配资源
if (needed[i][a])release = 0;
}
//如果进程已有所有资源可以执行,模拟一下执行完的时候,占用的资源还给系统的过程
if (release)
{
for (int a = 0; a < m; a++)
{
worked[a] += allocationed[i][a];
needed[i][a] = 0;
allocationed[i][a] = 0;
}
}
finished[i] = 1;//无论能否释放资源,我们都应该放入安全序列,因为这个资源申请我们已经处理了
int flag;
for (int a = 0; a < n; a++)//寻找不在序列里的进程时,需要不断从头遍历finished数组,因此要二重循环,从头遍历个n次就够了
{
flag = 0;//判断是否所有进程在安全队列中,如果是,可以退出循环了
for (int b = 0; b < n; b++)
{
if (finished[b])//如果b进程已经在队列了
continue;
flag = 1;//如果不在队列,满足它
if (test(worked,finished,needed, allocationed,b))//如果满足就安全了,那么找到了安全队列
finished[b]=1;
}
if (!flag) break;
}
if (!flag)return 1;
else return 0;
}
int main()
{
cin >> n >> m;
for (int i = 0; i < m; i++)//读入进程和资源数,默认资源从0开始命名
cin >> available[i];
for (int i = 0; i < n; i++)//初始化矩阵值
{
int id;
cin >> id;
for (int j = 0; j < m; j++)
cin >> allocation[id][j];
for (int j = 0; j < m; j++)
cin >> Max[id][j];
for (int j = 0; j < n; j++)
need[id][j] = Max[id][j] - allocation[id][j];
finish[i] = 1;//假设所有进程都已经在安全队列里
}
//开始处理资源申请,假设有三个申请,如果要测试书上用例,改成6就好
int num = 3;
for (int i = 0; i < num; i++)
{
int id, invalid = 0, wait = 0;
cin >> id;
finish[id] = 0;//id进程此时未加入队列
//读入数据
for (int j = 0; j < m; j++)
{
cin >> request[id][j];
if (request[id][j] > need[id][j])
invalid = 1;
else if (request[id][j] > available[j])
wait = 1;
}
//如果输入不合法
if (invalid)
{
cout << "进程" << id << "输入不合法" << endl;
for (int j = 0; j < m; j++)//当这次申请不存在
request[id][j] = 0;
continue;
}
//如果目前满足不了进程
if (wait)
{
cout << "进程" << id << "资源不够再等等" << endl;
continue;
}
if (test(available, finish, need, allocation,id))//输入合法且资源够,那分配试试
{
cout << "进程" << id << "可以分配" << endl;
//这波真分配
int release = 1;
for (int a = 0; a < m; a++)
{
available[a] -= request[id][a];
need[id][a] -= request[id][a];
allocation[id][a] += request[id][a];
if (need[id][a])release = 0;
}
//如果资源满足了可以执行,执行完记得还给系统
if (release)
{
for (int a = 0; a < m; a++)
{
//available[a] += request[id][a];
available[a] += allocation[id][a];
need[id][a] = 0;
allocation[id][a] = 0;
}
}
finish[id] = 1;//就算不能释放,也要加入安全序列,因为我们已经处理了这个资源申请
}
else cout << "进程"<<id<<"现在还不能分配" << endl;
for (int i = 0; i < n; i++)//看看别的进程能不能分配
{
if (finish[i]==0&&test(available, finish, need, allocation,i))
{
int release = 1;
cout << "进程" << i << "可以分配" << endl;
//这波真分配
for (int a = 0; a < m; a++)
{
available[a] -= request[i][a];
need[i][a] -= request[i][a];
allocation[i][a] += request[i][a];
if (need[i][a])release = 0;
}
//如果资源满足了可以执行,执行完记得还给系统
if (release)
{
for (int a = 0; a < m; a++)
{
//available[a] += request[id][a];
available[a] += allocation[id][a];
need[id][a] = 0;
allocation[id][a] = 0;
}
}
finish[i] = 1;//就算不能释放,也要加入安全序列,因为我们已经处理了这个资源申请
}
}
}
return 0;
}
和DFS对比
去掉test函数里模拟分配资源和释放资源的步骤,只看第三步的核心代码,是否有点相似呢
以下是老师用例运行结果
以下是我的改进用例运行结果
以下是书上用例的结果
有帮助的话可以点个赞,我会很开心的~
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?