这个学期学习操作系统,其实主要就是系统对于一些情况的应对算法,我们要做的就是写代码模拟这个情况,来了解操作系统是怎么解决的。
一、简介
我们要编写一个动态分配系统资源的程序,模拟死锁现象,观察死锁发生的条件,并采用适当的算法,有效地防止死锁的发生。设计一个几个并发进程共享m个系统资源的系统。进程可动态的申请资源和释放资源,系统按各进程的申请动态的分配资源。
系统应能选择是否采用防止死锁的算法,应设计多种防止死锁的算法,并能任意选择其中任何一种投入运行(这里只采用银行家算法),同时要求,在不采用防止死锁算法时观察死锁现象发生的过程,在使用防止死锁的算法时,了解在同样条件下防止死锁发生的过程。
二、算法
本次实验采用银行家算法防止死锁的发生。设有3个并发进程共享3种系统资源。程序采用人工输入各进程的申请资源序列。如果随机给各进程分配资源,就可能发生死锁,这也就是不采用防止死锁算法的情况。而按照一定的规则,为各进程分配资源,就可以防止死锁的发生。我们将采用银行算法。这是一种犹如“瞎子爬山”的方法,即探索一步,前进一步,行不通,再往其它方向试探,直至爬上山顶。这种方法是比较保守的,所花的代价也不小。
程序流程:
1、输入进程个数,资源种数,每种资源的最大值
2、依次未每个资源输入运行所需资源数,已有资源数
3、进入菜单选择,可以输出当前资源分配情况:每个进程的最大需求,已有资源,还需资源,系统可分配资源
4、进入菜单选择,可以判断当前是否未安全状态,如果是,输出资源分配过程
5、进入菜单选择,可以为某个进程申请资源,判断输入合法性,并修改数据
6、进入菜单选择,可以为某个进程释放资源,判断输入合法性,并修改数据
7、可以选择重新开始程序,即回到1,或选择退出程序
解释:程序分为三部分:完成程序流程,银行算法流程,安全性检测。银行算法的原理是先假定某一次分配成立,然后检查由于这次分配是否会引起死锁,即剩下的资源是不是能满足任一进程完成的需要。如这次分配是安全的(不会引起死锁),就实施本次分配,再作另一种分配试探,一直探索到各进程均满足各自的资源请求,防止了死锁的发生。
三、结果
四、代码
#include <iostream>
#include <vector>
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
using namespace std;
#define MAX 20
/*请输入进程个数和资源种类:3 3
请输入每种资源的总数:6 8 9
进程P0最大需求 已有资源: 4 5 2 2 0 1
进程P1最大需求 已有资源: 3 3 7 1 2 3
进程P2最大需求 已有资源: 2 4 6 0 3 1*/
enum Tag
{
False,True//枚举类型,值是int,所以可以赋值给int类型的数
};
class Banker
{
public:
Banker():I(0),R(0){};
int Init() //初始化进程资源
{
int sign = True;
cout<<"请输入进程个数和资源种类:";
int M,N;
cin>>M>>N;
if(M<=0||N<=0)return false;
I=M;R=N;
cout<<"请输入每种资源的总数:";
for(int i=0;i<R;++i)
{
cin>>memery[i];
if(memery[i]<0)sign=False;
}
for(int i = 0; i < I; ++i)
{
cout<<"进程P"<<i<<"最大需求 已有资源:"<<" ";
for(int j=0;j<R;++j)
{
cin>>Max[i][j];
if(Max[i][j]<0)sign=False;
}
for(int j=0;j<R;++j)
{
cin>>Allocation[i][j];
if(Allocation[i][j]<0)sign=False;
}
for(int j=0;j<R;++j)
{
Need[i][j]=Max[i][j]-Allocation[i][j];//计算各进程还需要的资源数
}
}
for(int i=0;i<R;++i)
{
int sum[MAX]={0};
for(int j=0;j<I;++j)
{
sum[i]+=Allocation[j][i];
}
Available[i]=memery[i]-sum[i]; //总的资源数-已分配的资源数
if(Available[i]<0)sign = False;
}
return sign;
}
int getI()
{
return I;
}
int getR()
{
return R;
}
void Display() //打印进程现在时刻资源分配情况
{
cout<<"现在时刻的状态:"<<endl;
printf("进程\t Max\t Allocation\t Need\t Available\n");
for(int i = 0; i < I; ++i)
{
printf("P%d\t",i);
for(int j = 0; j < R; ++j)
{
cout<<Max[i][j]<<" ";
}
printf("\t ");
for(int j = 0; j < R; ++j)
{
cout<<Allocation[i][j]<<" ";
}
printf("\t");
for(int j = 0; j < R; ++j)
{
cout<<Need[i][j]<<" ";
}
printf("\t ");
for(int j = 0; j < R; ++j)
{
if(i == 0)
cout<<Available[j]<<" ";
else
cout<<" "<<" ";
}
cout<<endl;
}
}
void Safe() //寻找安全序列
{
int work[MAX] = {0};
memcpy(work,Available,R*sizeof(int)); //将可利用的资源Available数组内容给work数组
FindSafe(work); //查找安全序列并打印
SafeNum.clear();//寻找安全序列后清空容器
}
//请求释放资源
void Requestrelease(int id,int* req)
{
assert(id>=0&&id<=I);
for(int i = 0; i < R; ++i) //判断某进程申请的资源是否是否小于等于其需要的或系统现所拥有的
{
if(req[i] > Allocation[id][i])
{
cout<<"警告:资源"<<i<<"超过此进程已有资源,已全部释放!"<<endl;
req[i] = Allocation[id][i];
}
if(req[i] < 0)
{
cout<<"警告:资源"<<i<<"为负数,未释放该资源!"<<endl;
req[i] = 0;
}
}
addnum(Available,req,R);
addnum(Need[id],req,R);
subnum(Allocation[id],req,R);
}
//请求资源寻找安全序列
void Request(int id,int* req)
{
assert(id>=0&&id<=I);
int work[MAX] = {0};
int need[MAX] = {0};
int Allocate[MAX] = {0};
int Av[MAX] = {0};
for(int i = 0; i < R; ++i) //判断某进程申请的资源是否是否小于等于其需要的或系统现所拥有的
{
if(req[i] > Need[id][i])
{
cout<<"警告:超过此进程需求!"<<endl;
return;
}
if(req[i] > Available[i])
{
cout<<"警告:申请量超过当前可用资源数!"<<endl;
return;
}
if(req[i] < 0)
{
cout<<"警告:申请量为负!"<<endl;
return;
}
}
//保存此进程原所需求资源、已分配资源和系统可利用资源Available
memcpy(need,Need[id],R*sizeof(int));
memcpy(Allocate,Allocation[id],R*sizeof(int));
memcpy(Av,Available,R*sizeof(int));
//修改Allocation、Need和Available变量,变为现在状态下此进程各项资源
addnum(Allocation[id],req,R);
subnum(Need[id],req,R);
subnum(Available,req,R);
memcpy(work,Available,R*sizeof(int));
FindSafe(work);//此时状态下寻找安全序列
if(SafeNum.size()==I)
{
cout<<"找到安全序列,为P"<<id<<"分配资源!";
cout<<endl;
}
//没有找到则改变回原状态
else
{
cout<<"根据银行家算法,本次分配会产生死锁,是否取消分配?Y/N:";
char cho;
cin>>cho;
if(cho=='N'||cho=='n')
{
cout<<"本次资源申请成功,建议检查死锁!"<<endl;
}
else
{
if(cho!='Y'||cho!='y')cout<<"输入有误,已取消本次分配!"<<endl;
else cout<<"已取消本次分配!"<<endl;
memcpy(Need[id],need,R*sizeof(int));
memcpy(Allocation[id],Allocate,R*sizeof(int));
memcpy(Available,Av,R*sizeof(int));
}
}
SafeNum.clear();//寻找安全序列后清空容器
}
protected:
void subnum(int* arr1, int* arr2,int n)
{
while(n--)
{
*arr1 = *arr1 - *arr2;
arr1++;
arr2++;
}
}
void addnum(int* arr1, int* arr2,int n)
{
while(n--)
{
*arr1 = *arr1+ *arr2;
arr1++;
arr2++;
}
}
bool comparenum(int* arr1,int* arr2)
{
for(int i = 0; i < R; ++i)
{
if(arr1[i] > arr2[i])
return false;
}
return true;
}
void FindSafe(int* work) //查找安全序列
{
int WorkCur[MAX][MAX] = {0};
vector<int> finish(I,0);//表示系统是否有足够资源分配给系统
int WorkPrev[MAX][MAX] = {0};
int j = 0;
int i = 0;
for(j=0;j<I;++j)//两层循环最慢的一种情况就是安全序列正好倒着
{
for(i=0;i<I;++i)
{
if(finish[i]== False)
{
//判断是否可以满足需求
if(comparenum(Need[i],work))//比较现有资源与进程需求
{
SafeNum.push_back(i); //记下进程号
finish[i] = True; //状态标记为已完成;
//更新数据
addnum(WorkPrev[i],work,R); //保存没分配前系统所有的资源,即将work中的资源数给WorkMartix
addnum(work,Allocation[i],R); //计算系统现在可利用资源数work==前work+Allocation
addnum(WorkCur[i],work,R); //前work+Allocation
}
}
}
if(SafeNum.size() == I)//表示进程已被分配完,找到安全序列
break;
if(i==I&&SafeNum.size()==0)//若比较一次完成后容器没有符合要求的进程直接退出
break;
}
if(SafeNum.size() != I) //若进程个数没有全部入进vector容器中,则没找到安全序列
{
cout<<"该状态不安全,建议选择释放部分资源!!!"<<endl;
return;
}
printsoure(WorkCur,finish,WorkPrev);
}
//打印安全序列
void printsoure(int WorkCur[][MAX],vector<int> finish,int WorkPrev[][MAX])
{
printf("安全序列为: ");
for(int i = 0; i < I; ++i)
{
printf("P[%d] ",SafeNum[i]);
}
cout<<endl;
printf("进程\t work\t need\t allocation\t work + allocation\t Finish\n");
for(int i = 0; i < I; ++i)
{
int id = SafeNum[i];
printf("P%d\t",SafeNum[i]);
for(int j = 0; j < R; ++j)
{
cout<<WorkPrev[id][j]<<" ";
}
printf("\t ");
for(int j = 0; j < R; ++j)
{
cout<<Need[id][j]<<" ";
}
printf("\t ");
for(int j = 0; j < R; ++j)
{
cout<<Allocation[id][j]<<" ";
}
printf("\t\t");
for(int j = 0; j < R; ++j)
{
cout<<WorkCur[id][j]<<" ";
}
printf("\t\t ");
cout<<finish[id]<<endl;
}
cout<<endl;
}
protected:
int I; //代表有几个进程
int R; //代表几类资源
int memery[MAX]; //资源的总数
int Max[MAX][MAX]; //对各类资源最大需求量
int Allocation[MAX][MAX]; //每个进程当前已分配各类资源数
int Need[MAX][MAX]; //每个进程当前的需求量
int Available[MAX]; //系统当前剩余可分配的各类资源
vector<int> SafeNum; //记录安全序列
};
int main()
{
//Banker banker = new Banker();
Banker banker;
int correct = banker.Init();
while(correct == False)
{
cout<<"系统可用资源数为负或输入数据为负!请重新输入!"<<endl;
correct = banker.Init();
}
while(1)
{
cout<<"*********************************************************"<<endl;
cout<<"** 银行家算法 **"<<endl;
cout<<"** 1. 查看现在时刻资源分配情况 **"<<endl;
cout<<"** 2. 查看现在时刻是否是安全状态 **"<<endl;
cout<<"** 3. 为进程--申请--资源 **"<<endl;
cout<<"** 4. 为进程--释放--资源 **"<<endl;
cout<<"** 5. 重新启动该程序--初始化所有数据 **"<<endl;
cout<<"** 0. 退出 **"<<endl;
cout<<"*********************************************************"<<endl;
cout<<"请选择:";
int ch = 0;
cin>>ch;
switch (ch)
{
case 0:
exit(0);
break;
case 1:
banker.Display();
break;
case 2:
banker.Safe();
break;
case 3:
{
int id = 0;
int request[MAX] = {0};
cout<<"请输入要申请的进程号:";
cin>>id;
cout<<"请输入各类资源个数:";
for(int i = 0; i < banker.getR(); ++i)
cin>>request[i];
banker.Request(id,request);
}
break;
case 4:
{
int id = 0;
int request[MAX] = {0};
cout<<"请输入要释放的进程号:";
cin>>id;
cout<<"请输入各类资源个数:";
for(int i = 0; i < banker.getR(); ++i)
cin>>request[i];
banker.Requestrelease(id,request);
}
break;
case 5:
{
int correct = banker.Init();
while(correct == False)
{
cout<<"系统可用资源数为负或输入数据为负!请重新输入!"<<endl;
correct = banker.Init();
}
}
break;
default:
cout<<"请重新输入!!!"<<endl;
break;
}
}
return 0;
}