emmmm。。这个是很久以前做的 为了防止文件丢失 直接把实训报告贴在这以作保存
用程序实现银行家算法
1. 课程设计内容
整个银行家算法程序包括
void showstart(int m, int n);// 以数组形式显示出m 个进程对 n 类资源已有资源
void showneed(int m, intn);// 以数组形式显示出 m 个进程对 n 类资源仍需求资源
void showinventory(intn);//以数组形式显示出 资源的库存
void showall(int m, intn);//所有数据显示
bool IsNotSafe(int m,int n);//系统安全性检查,判断不安全
void ChangData(int n,int k);//申请资源数不超库存和需求,改变数据
void NotSafeBack(int n,int k);//判断不安全,将数据还回去
以及主程序intmain()
2. 背景知识
银行家算法是一个用来避免系统进入死锁状态的算法,用它可以判断系统的安全性,如果系统当前处于安全状态,则可以为申请资源的进程分配资源,如果不是安全状态,则不能为申请资源的进程分配资源。
银行家算法执行过程中,首先判断申请资源的进程所申请的资源数目是否合法,若是合法的,则可以为其进行试分配,再利用安全性算法求出安全序列,·如果存在安全序列,则说明可以给申请资源的进程分配资源,分配成功,继续为其它进程服务。如果找不到安全序列,则说明为该进程分配资源后系统会进入不安全状态,所以不能为该进程分配资源,使该进程进入阻塞状态。若申请资源的进程申请的资源数目不合法,则不需要进行试分配,直接使其进入阻塞状态,处理其他申请资源的进程。
3. 设计步骤与方法
3.1. 步骤1:需求分析
3.1.1. 步骤1.1:问题描述
当系统在进行资源管理时,如果对进程申请的资源分配不当,可能会使系统进入死锁状态,因而后面到来的进程也无法顺利执行。银行家算法中,要对当前申请资源的进程申请资源的数目进行判断,如果可以试分配,则试求出一个安全序列,如果可以求出,则说明给这个进程分配资源后系统不会进入不安全状态,将该进程申请的资源分配给他,若求不出安全序列,则说明将资源分配给该进程后系统会进入不安全状态,所以就使该进程进入阻塞状态,等待以后可以分配资源时再执行该进程,然后系统继续服务其它进程。通过这样一个过程,可以有效避免系统进入死锁状态。
3.1.2步骤1.2:基本要求
(1)对各个进程的进程名,最大需求资源,已分配资源,系统可用资源等进行有序的输入。
(2)对申请资源的进程要有合法性判断(如进程名,申请资源数等)。
(3) 若有进程申请资源,首先要对它申请的资源数进行判断。
(4) 在上面判断合法的前提下进行试分配,利用银行家算法求出安全序列,如果可以求出安全序列,则为该进程分配资源,询问是否继续输入,否则使它报错,退回已请求资源,询问是否继续输入。
3.1.3步骤1.3:概要分析
在避免死锁的算法中,允许进程动态地申请资源,系统在进行资源分配之前,先计算资源分配的安全性。若此次分配不会使系统进入不安全状态,便将资源分配给该进程否则进程等待。
所谓安全状态是指系统能按某种顺序如<p1,p2,……,pn>(称<p1,p2,……,pn>为安全序列),就这样来为每个进程分配资源,直至最大需求。使每个进程都可以顺序地执行完毕。若系统不存在这样一个安全序列,那么系统此时会进入不安全状态。
虽然并非所有的不安全状态都会产生死锁状态,但当系统进入不安全状态后,便可能进而进入死锁状态;反之,只要系统处于安全状态,系统便可避免进入死锁状态。因此,避免死锁的实质在于,如何使系统不进入不安全状态,银行家算法就是用来判断某种情况会不会进入不安全状态。
3.2. 步骤2:设计
3.2.1步骤2.1:概要设计
3.2.2步骤2.2:详细设计
三个主要函数:1改变数据 2.判断不安全,将数据还回去3.判断安全性并找出安全序列
void ChangData(int n, int k);//申请资源数不超库存和需求,改变数据
{
for(int j = 0; j < n; j++)
{
Inventory[j]= Inventory[j] - Request[j];//库存-请求
Start[k][j]= Start[k][j] + Request[j];//现有+请求
Need[k][j]= Need[k][j] - Request[j];//需求-请求
}
}
void NotSafeBack(int n, int k);//判断不安全,将数据还回去
{
cout<<"正在退回资源"<<endl;
for (int j = 0;j < n; j++)
{
Inventory[j]= Inventory[j] + Request[j];
Start[k][j]= Start[k][j] - Request[j];
Need[k][j]= Need[k][j] + Request[j];
}
cout<<"已退回资源"<<endl;
}
bool IsNotSafe(int m, int n);//系统安全性检查,判断不安全
{
int work[100];//n/表示剩下可供分配的有效资源数
intfinish[100];//m表示第i个进程是否可以运行完
inttemp[100];//mtemp[]用来记录进程安全执行的顺序
int temp1 ;//标记为需要资源[j]小于剩余可分配有效资源[j]
int i, j, k =0;
int Reset=0 ;//判断是否要重循环
for (i = 0; i< m; i++)//finish[]初始化为否
{
finish[i]= 0;
}
for (j = 0;j<n; j++)//初始化剩余可分配有效资源数为库存值
{
work[j]= Inventory[j];
}
for (i = 0;i<m; i++)//遍历进程看是否有刚好满足的
{
if(Reset==1)
{
i= 0;//重头来过以免漏掉
}
Reset=0;
temp1 =1;//标记为需要资源[j]小于剩余可分配有效资源[j]
if (finish[i]== 1)continue;//已经分配过的跳掉
for (j =0; j<n; j++)
{//遍历资源i进程还需要的资源[j]是否大于剩余可分配有效资源[j]
if(Need[i][j]>work[j])
{
temp1= 0;
break;
}
}
if(finish[i] == 0 && temp1 == 1)//未分配过并且需要资源[j]小于剩余可分配有效资源[j]
{//i进程还需要的资源[j]小于剩余可分配有效资源[j]
//那么这个进程就可以执行完然后将资源归还系统
//即可分配有效资源[j]=该进程全部现有资源[j]+原可分配有效资源[j]
for(j = 0; j<n; j++) //for1
{
work[j]= work[j] + Start[i][j];
}
finish[i]= 1;
temp[k]= i+1;//保存序列
k++;
Reset=1;
}
}
for (i = 0;i<m; i++) //遍历下看看是否有安全序列
{
if(finish[i]==0)
{
cout<< endl;
cout<< " 系统不安全!!! 本次资源申请不成功!!!"<< endl;
cout<< endl;
return1;
}
}
//正确返回否值
cout <<endl;
cout <<" 经安全性检查,系统安全,本次分配成功。" << endl;
cout <<endl;
cout <<" 本次安全序列:";
for (i = 0;i<m; i++)
{
cout<< "进程" << temp[i] ;
if(i<m-1)cout<<"->";
}
cout <<endl << endl;;
return 0;
}
4. 设计结果及分析
输入数据后经过安全性判断恰好能找到安全序列
5. 问题及心得体会
本来以为这个程序应该很简单很快就能好,结果实际操作起来却花了将近2周,虽然断断续续。使用的是好久没碰的c++,感觉特别是数组有点忘,就先看了几天《易学c++》温习一下。
最开始我尝试了个简单版本的,就是以2维数组将一切包括进程数,资源类数,初始进程拥有资源,进程最大需求值先提前给出。然后用户只能输入请求的值。相对简易,大致为后来修改立下奠基。
第一次修改将原来默认给定的数值全部改为动态输入的数据,以数组来存储,这就有了第二代版本,唯一缺点是我把初始进程拥有资源定义为0,这就大大增加了测试的麻烦程度,每次都得1个个数据申请判断,很烦因此推动我继续改进版本。
第三代版本出现了,这一次,我将它更改为可输入进程数,资源类数,初始进程拥有资源,还可多次输出,并添加上最为核心的安全性判断法。然而,这一改变过程,却导致很多错误,导致一直卡在瓶颈,导致我一再几天没有进度。通过思考还有将每次变化数据显示出来,我很快发现了问题所在。
由于第二次版本的修改,我将初始进程拥有资源定义为0,因此当时的第m个进程还需要第n类资源的资源量(Need值)可以看作是等于第m个进程对第n类资源最大资源需求量(MAX值),所以当时也没注意,才发现这个导致我测试频频饮恨的罪魁祸首;接着由于数组存在i[0],这与我们通俗叫法中的第一第二…这种从一开始的相差了一位,导致常常出错,经过数据测试,我也及时通过+1和-1来解决这个问题;然后判断安全性那里是我花了我最长时间的,总是搞不清楚哪里出错,其中一个就是缺乏对分配完成与未完成区别对待,导致多次将分配完的数据重复输入,后来设了一个finish[i]来标识是否完成分配同时循环开头用if语句判断是否跳过,缩短了时间;最后还是在安全性这里,经过多次数据测试发现,一些例题能成功找出正确的安全序列,有些却报错,再对那些报错和正确的数据断点观察后发现,原来由于i++的原因导致开始时第一个数被跳掉,因此添加判断标志Reset=0,来判断是否要重循环,是的话i=0,以免漏掉。以上都是我所遇到的典型错误,细小那些就不多提。
经过这次课程设计,让我重新体会到编程的乐趣,那种专研后找到解决错误的快感,同时加深了我对银行家算法以及c++的了解,这次课程设计使我受益匪浅。
源码
#include<iostream>
#include<iomanip>
#include<string>
using namespace std;
//int Start[5][4] = { { 0, 0, 3, 2 }, { 1, 0, 0, 0 }, { 1, 3, 5, 4 }, { 0, 3, 3, 2 }, { 0, 0, 1, 4 } };
int Start[100][100];//m个进程对n类资源初始拥有量
int MAX[100][100];//m个进程对n类资源最大资源需求量
int Need[100][100];//m个进程还需要n类资源的资源量
int Inventory[100];//库存量
int Request[100];// 需要资源
void showstart(int m, int n);// 以数组形式显示出 m 个进程对 n 类资源已有资源
void showneed(int m, int n);// 以数组形式显示出 m 个进程对 n 类资源仍需求资源
void showinventory(int n);//以数组形式显示出 资源的库存
void showall(int m, int n);//所有数据显示
void ChangData(int n, int k);//申请资源数不超库存和需求,改变数据
void NotSafeBack(int n, int k);//判断不安全,将数据还回去
bool IsNotSafe(int m, int n);//系统安全性检查,判断不安全
int main()
{
//初始化 m个进程对n类资源最大资源需求量
int m, n;//输入总进程数m和总资源类数n
cout << "总进程数为:";
cin >> m;
cout << "总资源数类数:";
cin >> n;
//库存量输入
for (int j = 0; j < n; j++)
{
cout << "第" << j + 1 << " 类总资源数为:";
cin >> Inventory[j];
}
showinventory(n);
//测试数据int MAX[4][3]={ { 8, 6, 7 }, { 6, 7, 8 }, { 4, 5, 2 }, { 4, 6, 3 } };
for (int i = 0; i < m; i++)
{
for (int j = 0; j <n; j++)
{
cout << "第" << i + 1 << "个进程对第" << j + 1 << "类资源的最大需求量为:";
cin >> MAX[i][j];
}
cout << endl;
}
//显示给客户看已输入的m个进程对n类资源最大资源需求量 以便下一步输入
cout << "现在以数组形式显示出 " << m << " 个进程对 " << n << " 类资源最大资源需求量" << endl;
for (int i = 0; i < m; i++)
{
cout << "{";
for (int j = 0; j < n; j++)
{
cout << setw(2) << MAX[i][j];
if (j<n - 1)cout << ",";
}
cout << "}" << endl;
}
//m个进程已经得到n类资源的资源量初始化
cout << "请初始化各线程现有的资源" << endl;
for (int i = 0; i < m; i++)
{
for (int j = 0; j <n; j++)
{
cout << "第" << i + 1 << "个进程已拥有的第" << j + 1 << "类资源数为:";
cin >> Start[i][j];
Need[i][j] = MAX[i][j] - Start[i][j];//需求量应当为最大值-初始拥有的
}
cout << endl;
}
showneed(m, n);
cout << endl;
showstart(m, n);
//正式运行
//int need[100][100];//m个进程还需要n类资源的资源量
//int request;// 需要资源
char flag = 'y';
while (flag == 'y' || flag == 'Y')//while1
{
//初始化请求资源
for (int i = 0; i < n; i++)
{
Request[i] = 0;
}
int rj = -100;
int rl = -100;
//第一步输入申请的进程号并判断是否合法
while (rj <= 0 || rj >m) //while2
{
cout << " 请输入需要申请资源的进程号(从1到" << m << "!):";
cin >> rj;
if (rj <= 0 || rj >m)
{
cout << " 输入的进程号不存在,请重新输入!" << endl;
continue;
}
} //end while2
//
//第二步输入要申请的资源
for (int j = 0; j <n; j++)
{
rl = j;
cout << "您希望为第 " << rj << " 进程申请多少 " << rl + 1 << "类资源:";
cin >> Request[rl];
//对申请资源数是否超库存和需求的判断
if (Request[rl]>Inventory[rl])
{
cout << endl;
cout << "您的请求无法完成,该" << rl << "类资源并没有那么多库存" << endl;
cout << endl;
}
else if (Request[rl]>Need[rj - 1][rl])
{
cout << endl;
cout << " 进程" << rj << "申请的资源数大于它还需要的" << rl << "类资源的资源量!";
cout << "申请不合理,出错!请重新选择!" << endl << endl;
cout << endl;
}
}
ChangData(n, rj - 1);
if (IsNotSafe(m, n) == 1)
{
showall(m, n);
//判断不安全,将数据还回去
NotSafeBack(n, rj - 1);
}
showall(m, n);
//判断是否要继续
cout << "请输入是否要继续申请资源(y / n)?" << endl;
cin >> flag;
}//end while1
}
//显示类函数
void showstart(int m, int n)
{
cout << "现在以数组形式显示出 " << m << " 个进程对 " << n << " 类资源已有资源" << endl;
for (int i = 0; i < m; i++)
{
cout << "{";
for (int j = 0; j < n; j++)
{
cout << setw(2) << Start[i][j];
if (j < n - 1)cout << ",";
}
cout << "}" << endl;
}
}
//m个进程还需要n类资源的资源量
void showneed(int m, int n)
{
cout << "现在以数组形式显示出 " << m << " 个进程对 " << n << " 类资源仍所需资源" << endl;
for (int i = 0; i < m; i++)
{
cout << "{";
for (int j = 0; j < n; j++)
{
cout << setw(2) << Need[i][j];
if (j < n - 1)cout << ",";
}
cout << "}" << endl;
}
}
void showinventory(int n)
{
/*
for (int j = 0; j < n; j++)
{
cout << "第" << j +1<< " 类总资源数为:";
cout << Inventory[j];
cout << endl;
}*/
cout << "现在以数组形式显示出 " << n << " 类总资源数为:" << endl;
cout << "{";
for (int j = 0; j < n; j++)
{
cout << setw(2) << Inventory[j];
if (j < n - 1)cout << ",";
}
cout << "}" << endl;
}
void showall(int m, int n)
{
showstart(m, n);
showneed(m, n);
showinventory(n);
}
void ChangData(int n, int k)
{
for (int j = 0; j < n; j++)
{
Inventory[j] = Inventory[j] - Request[j];//库存-请求
Start[k][j] = Start[k][j] + Request[j];//现有+请求
Need[k][j] = Need[k][j] - Request[j];//需求-请求
}
}
void NotSafeBack(int n, int k)
{
cout << "正在退回资源" << endl;
for (int j = 0; j < n; j++)
{
Inventory[j] = Inventory[j] + Request[j];
Start[k][j] = Start[k][j] - Request[j];
Need[k][j] = Need[k][j] + Request[j];
}
cout << "已退回资源" << endl;
}
bool IsNotSafe(int m, int n)
{
int work[100];//n/表示剩下可供分配的有效资源数
int finish[100];//m表示第i个进程是否可以运行完
int temp[100];//mtemp[]用来记录进程安全执行的顺序
int temp1;//标记为需要资源[j]小于剩余可分配有效资源[j]
int i, j, k = 0;
int Reset = 0;//判断是否要重循环
//finish[]初始化为否
for (i = 0; i < m; i++)
{
finish[i] = 0;
}
//初始化剩余可分配有效资源数为库存值
for (j = 0; j<n; j++)
{
work[j] = Inventory[j];
}
for (i = 0; i<m; i++)//遍历进程 看是否有刚好满足的
{
if (Reset == 1)
{
i = 0;//重头来过 以免漏掉
}
Reset = 0;
temp1 = 1;//标记为需要资源[j]小于剩余可分配有效资源[j]
if (finish[i] == 1)continue;//已经分配过的跳掉
for (j = 0; j<n; j++)
{
//遍历资源 i进程还需要的资源[j]是否大于剩余可分配有效资源[j]
if (Need[i][j]>work[j])
{
temp1 = 0;
break;
}
}
if (finish[i] == 0 && temp1 == 1)//未分配过并且需要资源[j]小于剩余可分配有效资源[j]
{
//i进程还需要的资源[j]小于剩余可分配有效资源[j]
//那么这个进程就可以执行完 然后将资源归还系统
//即可分配有效资源[j]=该进程全部现有资源[j]+原可分配有效资源[j]
for (j = 0; j<n; j++) //for1
{
work[j] = work[j] + Start[i][j];
}
finish[i] = 1;
temp[k] = i + 1;//保存序列
k++;
Reset = 1;
}
}
for (i = 0; i<m; i++) //遍历下看看是否有安全序列
{
if (finish[i] == 0)
{
cout << endl;
cout << " 系统不安全!!! 本次资源申请不成功!!!" << endl;
cout << endl;
return 1;
}
}
//正确返回否值
cout << endl;
cout << " 经安全性检查,系统安全,本次分配成功。" << endl;
cout << endl;
cout << " 本次安全序列:";
for (i = 0; i<m; i++)
{
cout << "进程" << temp[i];
if (i<m - 1)cout << "->";
}
cout << endl << endl;;
return 0;
}