一、实验目的:
通过对银行家算法的模拟加深对避免死锁的理解,掌握银行家算法和安全性测试算法;
二、实验内容:
系统中有m个同类资源,被n个进程共享,每个进程对资源的最大需求数分别为S1、S2、…、Sn,且Max(Si)<=m(i=1,2,…,n)。进程可以动态地申请资源和释放资源。编写一个程序,实现银行家算法模拟分配资源以及进行安全性检测。当系统将资源分配给某一进程而不会死锁时,就分配之。否则,推迟分配,并显示适当信息。
三、实验要求:
- 将本实验分成两个阶段,第一阶段实现系统安全性检测算法(在系统安全的情况下要求输出安全序列), 第二阶段实现银行家算法。
- 要求用户能自主地输入不同的向量矩阵。
- 程序能正确输出不同的运算结果。
- 程序应具备良好的容错能力。
首先是头文件和预处理
#include<iostream>
#include<fstream>
#define pnum 5
#define rnum 3
pnum是processnum也就是进程数量,rnum是resourcenum也就是资源数量,这是一个关于如何合理的分配资源给进程的算法,在操作系统书上有讲解,希望读者区看看。
//定义安全性算法的数据结构
int sign[pnum],//安全序列
work[pnum][rnum],//记录要显示的work,由算法种的work赋值得到,方便打印输出
workAll[pnum][rnum];//work+allocation
//定义银行家算法的数据结构
int Available[pnum],//可用资源向量available
Max[pnum][rnum],//最大需求向量,每个进程的最大需求
Allocation[pnum][rnum],//分配矩阵,相当于当前已经分配了
Need[pnum][rnum];//max-allocation,当前还需资源数目向量
根据书上的内容可以作出如下的定义,银行家算法的可用资源,最大等(有批注),安全性算法的work是为了显示,后面的算法中会有体现,work+allocation是根书上保持一致所以这样的一个定义,具体的可以根据书上的表格进行比较,话不多说,老规矩,main函数分析。
首先在main函数中我们是需要申请多少的资源,是哪个进程申请,所以我们需要定义个request二维数组,进行一个资源的申请,行为进程pnum列为资源rnum
这时候,看了我前面的应该知道,我们需要进行一个创建,我们最大资源是多少,有多少个进程什么什么的,这些可以根据书上的已知条件,从而知道我们有多少数据需要用户进行一个输入。
creat函数进行一个封装,初始化
基本思想:将max,allocation,need,available数组装载数值,有些是一维,有些是二维,根据书上的已知条件可以得到如何创建,这里可能有些读者没书,在此给出代码
//初始化
void creat(){
for(int i = 0;i<pnum;i++){
cout<<"请输入第 "<<i<<" 个进程的数据:"<<endl;
cout<<"MAX:第"<<i<<"个进程一共需要申请多少个资源(A B C):";
for(int j=0;j<rnum;j++)
cin>>Max[i][j];
cout<<"Allocation:已获得的资源数量(A B C): ";
for(int j=0;j<rnum;j++)
cin>>Allocation[i][j];
cout<<"Need:还需要的资源数量(A B C): ";
for(int j=0;j<rnum;j++)
cin>>Need[i][j];
if(i==0){
cout<<"Available:现有资源的数量(A B C): ";
for(int j = 0;j < rnum;j++)
cin>>Available[j];
}
}
}
这时候我们回到我们的main,创建好了之后我们需要输入request数组中是哪个进程申请资源数量为多少,为了让读者阅读方便,在此也给出代码
while(true){
cout<<endl<<"请输入Request[进程标号i][资源类型j]:"<<endl;
cout<<"进程i=:";
cin>>i;
cout<<"各类资源数量(A B C): ";
for(int j = 0;j < rnum;j++)
cin>>Request[i][j];
cout<<endl;
//执行银行家算法
int res = Banker(i,Request);
//输出每次判断产生的执行序列
cout<<endl<<"当前的资源分配表:"<<endl;
show(res);
}
你会发现有banker里面的参数是进程几申请资源,最终返回的结果用来输出,那么我们的show应该如何的进行定义呢?
我们得显示我们的资源分配表,如果说安全性算法后还有一个安全队列,我们得输出安全性队列下的work等一系列,如果没有,我们就输出我们各个进程初始信息,all+need+available。让用户明白自己的申请的问题出错在哪。show:资源分配表的定义
首先show函数得接收一个值,res,表示有无安全序列,如果有,就是我的进程数,如果没有,就是不能构成安全序列我们需要输出它的初始信息
这里直接给源码,希望读者读懂后可以评论区留言说说你的理解
void show(int res){
if(res == pnum){
cout<<" 进程号--"<<" Work[A,B,C]"
<<" Need[A,B,C]"<<" Allocation[A,B,C]"<<" Work+Allocation[A,B,C]"<<" Finish"<<endl;
for(int i = 0;i < pnum;i++) {
for(int j = 0;j < rnum;j++)
cout<<work[sign[i]][j]<<" ";
cout<<' '<<' ';
for(int j = 0;j < rnum;j++)
cout<<Need[sign[i]][j]<<" ";
cout<<' '<<' ';
for(int j = 0;j < rnum;j++)
cout<<Allocation[sign[i]][j]<<" ";
cout<<' '<<' ';
for(int j = 0;j < rnum;j++)
cout<<workAll[sign[i]][j]<<" ";
cout<<' '<<' ';
cout<<"true"<<endl;
}
cout<<endl<<"安全序列为:{p["<<sign[0]<<"]";
for(int m = 1;m<pnum;m++){
cout<<",p["<<sign[m]<<"]";
}
cout<<"}"<<endl;
}
else{//没通过输出信息
cout<<" 进程号--"<<" Allocation[A,B,C]"
<<" Need[A,B,C]"<<" Available[A,B,C]"<<endl;
for(int k = 0;k < 5;k++){
cout<<' '<<"P["<<k<<"]"<<' '<<' ';
for(int j = 0;j < 3;j++)cout<<Allocation[k][j]<<" ";
cout<<' '<<' ';
for(int j = 0;j < 3;j++)cout<<Need[k][j]<<" ";
cout<<' '<<' ';
if(k == 0) {
for(int j = 0;j < 3;j++)
cout<<Available[j]<<" ";
}
cout<<endl;
}
}
}
现在进入正题
银行家算法banker(i,request[][rnum])
基本思想:第一步,//判断request内的资源是否比可用总数和进程i总共所需的大小,这是基本的条件
如何的实现呢?
for(int j = 0;j < rnum;j++) {
if(Request[i][j] > Need[i][j]){
cout<<"分配失败------>"<<endl<<"所需资源数超出其宣布的最大值!"<<endl;
return 0;
} else if(Request[i][j] > Available[j]) {
cout<<"分配失败------>"<<endl<<"无足够资源,p["<<i<<"]需要进行wait"<<endl;
return 0;
}
}
如果通过了,我们试着分配资源,进行安全性算法,如果没通过就直接返回了error,也会输出提示信息。
尝试分配资源我们应该怎么做呢?
首先让资源总数available减去request,让进程的allocation加上申请的,need也需要减去request。
大致理解:因为你申请了资源现在在假定分配,所以分配给你了系统的可用资源就要减少,当前进程的已用资源就要增加,目前还需资源就也要减少,因为系统已经满足你的需求了。
for(int j = 0;j < rnum;j++) {
Available[j] = Available[j] - Request[i][j];
Allocation[i][j] = Allocation[i][j] + Request[i][j];
Need[i][j] = Need[i][j] - Request[i][j];
}
执行安全性算法,根据安全性算法的返回值,确定是否有队列,最终输出显示的情况
后续代码我只给出执行安全性算法,如何让系统交互做的更好留给读者。
int n = Safe(Available,Need,Allocation);
cout<<endl;
if(n == pnum) {//有5个'true'返回1,表示此时刻安全
接下来来到安全性算法safe,它带了参数available和need和allocation
我们为了方便运算,原来的work为了存放available总数加上释放,所以我们这里新建一个work数组,它是一维的,因为它只需要将一组的数据进行一个传递,finish数组的定义为了判断是否有一个队列,所以它的大小为pnum。这里给出定义,ijmn是根据我的需求进行一个添加
int Safe(int Available[],int Need[][rnum],int Allocation[][rnum]) {
int i=0,j=0,m=0,n=0;
int Work[rnum],Finish[pnum] = {0,0,0,0,0};
接下来我们将我们的可用资源数目给我们的work临时一维数组。
进入一个大while,只要我们的i<进程总数pnum我们就继续在循环中找。这里你应该明白i是为了计数,看看有无这么多的进程完成,如果实在没有我们的扫描也会结束,到时候finish和i的值都不是理想值
只要对应的finish[i]是等于0 的说明还没有被加入就绪队列,首先判断现有的资源总量能否满足它的需求,可以满足我们就进行一个分配。这里分配后直接释放了,所以我们可以直接让work加上allocation中当前i进程的已用资源allocation,在这之前用我们的work二维数组记录下我们当前的work再去加进行一个变化,这样在循环中,work中就是显示未释放的状态中的可用资源,让我们的workall等于我们的一维数组work,有些许绕,我附上小部分的代码,希望读者钻研一下。
if(j == rnum){//如果need的三个资源都可以被满足,就分配并且释放和记录
for(int k = 0;k < rnum;k++){
work[i][k] = Work[k];//记录分配前的可用的资源总数
Work[k] = Work[k]+Allocation[i][k];
workAll[i][k] = Work[k];
}
如果我们这一步成功了,说明是可以分配的,让我们的安全序列数组sign中的第一个m变成i。finish[i]=1,i=-1,m++.
i 等于-1是因为在我们的if(Finish[i]==0){后还有一段代码,我们慢慢分析
我们是从头开始扫描,所以如果没加入,或者已经加入过了我们必须让我们的i++,让我们的j(用于检查可用资源是否满足的一个变量)归零。所以在if中我们的i=-1,在外++就变成了0,就是继续从首部查找。
最终根据finish中是否有0,我们可以得到我们是该返回pnum还是其他数字了。
到此已经讲述完了,希望读者能够仔细思考一下问题,后续结果有人提问我再在评论区更新!!!