广州大学学生实验报告
开课学院:计算机科学与网络工程学院
实验室:计算机软件实验室
计科183
实验二 银行家算法
一、实验目的
1、了解什么是操作系统安全状态和不安全状态;
2、了解如何避免系统死锁;
3、理解银行家算法是一种最有代表性的避免死锁的算法,掌握其实现原理及实现过程。
二、实验内容
根据银行家算法的基本思想,编写和调试一个实现动态资源分配的模拟程序,并能够有效避免死锁的发生。
一、实验原理
进程申请资源时,系统通过一定的算法判断本次申请是否不可能产生死锁(处于安全状态)。若可能产生死锁(处于不安全状态),则暂不进行本次资源分配,以避免死锁。算法有著名的银行家算法。
1、什么是系统的安全状态和不安全状态?
所谓安全状态,是指如果系统中存在某种进程序列<P1,P2,…,Pn>,系统按该序列为每个进程分配其所需要的资源,直至最大需求,则最终能使每个进程都可顺利完成,称该进程序列<P1,P2,…,Pn,>为安全序列。
如果不存在这样的安全序列,则称系统处于不安全状态。
2、银行家算法
把操作系统看作是银行家,操作系统管理的资源相当于银行家管理的资金,进程向操作系统请求分配资源相当于用户向银行家贷款。
为保证资金的安全,银行家规定:
(1) 当一个顾客对资金的最大需求量不超过银行家现有的资金时就可接纳该顾客;
(2) 顾客可以分期贷款,但贷款的总数不能超过最大需求量;
(3) 当银行家现有的资金不能满足顾客尚需的贷款数额时,对顾客的贷款可推迟支付,但总能使顾客在有限的时间里得到贷款;
(4) 当顾客得到所需的全部资金后,一定能在有限的时间里归还所有的资金。
操作系统按照银行家制定的规则设计的银行家算法为:
(1)进程首次申请资源的分配:如果系统现存资源可以满足该进程的最大需求量,则按当前的申请量分配资源,否则推迟分配。
(2)进程在执行中继续申请资源的分配:若该进程已占用的资源与本次申请的资源之和不超过对资源的最大需求量,且现存资源能满足该进程尚需的最大资源量,则按当前申请量分配资源,否则推迟分配。
(3)至少一个进程能完成:在任何时刻保证至少有一个进程能得到所需的全部资源而执行到结束。
银行家算法通过动态地检测系统中资源分配情况和进程对资源的需求情况来决定如何分配资源,并能在确保系统处于安全状态时才把资源分配给申请者,从而避免系统发生死锁。
二、实验中用到的系统调用函数
因为是模拟程序,可以不使用系统调用函数。
三,流程图:
程序流程图:
算法流程图:
2、对算法所用的数据结构进行说明;
n:进程数,由自己输入需要多少个进程
m:资源总类数m=3
Max[n][m]:每个进程每种资源的最大需求量,随机赋值
allocation[n][m]:每个进程每种资源已经分配的资源量,随机赋值
need[n][m]:每个进程每种资源还可能需要请求的总量
Request[n][m]:每个进程每种资源的请求量
Work[m]:工作向量,即可向正在运行的进程分配的资源量
bool Finish[n]:进程是否结束
WaddA[n][m]:记录Work+Allocation
p[n]:安全监测记录进程完成的顺序
work[n][m]:记录Work
available[m]:可利用资源向量,随机赋值
Print():输出当前各个进程的资源情况
print_sequence():输出安全状态下各个进程可以顺利完成的顺序
Safety():判断系统是否处于安全状态
init2():对各个进程的资源进行随机赋值
Banker():银行家算法核心部分
4、 编写程序并调试
#include
#include
#include
#include
void menu()
{
printf("\n");
printf("\n");
printf("\t1. 初始化\n");
printf("\t2. 查看当前资源分配表\n");
printf("\t3. 请求资源\n");
printf("\t4. 退出\n");
printf("\t请选择:\n");
}
void print(int m,int n,int Max[][3],int allocation[][3],int *available,int need[][3]) //对当前各个进程的最大需求量,已分配资源量,可用资源量和所需资源量的输出打印
{
printf("\tMax |\tAllo |\tNeed |\tAvalia\n");
for (int i = 0; i < n; i++)
{
printf("p%d\t",i);
for (int j = 0; j < m; j++)
{
printf("%d ",Max[i][j]);
}
printf("\t");
for (int j = 0; j < m; j++)
{
printf("%d ",allocation[i][j]);
}
printf("\t");
for (int j = 0; j < m; j++)
{
printf("%d ",need[i][j]);
}
printf("\t");
if (i == 0)
{
for (int i = 0; i < m; i++)
{
printf("%d ",available[i]);
}
printf("\n");
}
else
printf("\n");
}
}
void print_sequence(int m, int n, int allocation[][3], int need[][3],int *p,int work[][3],int WaddA[][3],bool *Finish) //打印出可以在安全状态下不断执行到全部进程完毕的顺序过程
{
printf("\tWork |\tNeed |\tAllo |\tW+A | Finish\n");
for (int i = 0; i < n; i++)
{
printf("P%d \t",p[i]);
for (int j = 0; j < m; j++)
{
printf("%d ",work[p[i]][j]);
}
printf("\t");
for (int j = 0; j < m; j++)
{
printf("%d ",need[p[i]][j]);
}
printf("\t");
for (int j = 0; j < m; j++)
{
printf("%d ",allocation[p[i]][j]);
}
printf("\t");
for (int j = 0; j < m; j++)
{
printf("%d ",WaddA[p[i]][j]);
}
printf("\t");
printf("%d\n",Finish[p[i]]);
}
}
bool safety(int m, int n, int allocation[][3], int *available, int need[][3],int *Work,bool *Finish,int work[][3],int WaddA[][3],int *p) //判断系统是不是处于安全状态
{
int w = 0;
for (int j = 0; j < m; j++)
{
Work[j] = available[j];
}
for (int i = 0; i < n; i++)
Finish[i] = false;
int count = 0;
while (1)
{
for (int i = 0; i < n; i++)
{
if (Finish[i] == false)
{
int f1 = 1;
for (int j = 0; j < m; j++)
{
if (need[i][j] > Work[j])
{
f1 = 0;
}
}
if (f1 == 1)
{
for (int j = 0; j < m; j++)
{
work[i][j] = Work[j];
Work[j] = Work[j] + allocation[i][j];
WaddA[i][j] = Work[j];
}
Finish[i] = true;
p[w++] = i;
count = 0;
}
}
}
count++;
if (count >= n)
break;
}
int flag = 1;
for (int i = 0; i < n; i++)
{
if (Finish[i] == false)
{
flag = 0;
}
}
if (flag == 1)
{
return true;
}
else
{
return false;
}
}
void init2(int m, int n, int Max[][3], int allocation[][3], int *available, int need[][3], int *Work, bool *Finish, int work[][3], int WaddA[][3], int *p) //以随机数给各个进程进行全新的赋值
{
for (int i = 0; i < n; i++)
{
printf("以随机数输入进程p%d的资源分配情况:\n",i);
printf("Max:");
for (int j = 0; j < m; j++)
{
Max[i][j] = rand() % 10;
printf("%d\t",Max[i][j]);
}
printf("\nAllocation:\n");
for (int j = 0; j < m; j++)
{
allocation[i][j] = rand() % 10;
while (allocation[i][j] > Max[i][j])
{
allocation[i][j] = rand() % 10;
}
printf("%d\t",allocation[i][j]);
}
}
for (int i = 0; i < n; i++)
{
for (int j = 0; j < m; j++)
{
need[i][j] = Max[i][j] - allocation[i][j];
}
}
printf("\n以随机数输入当前可用资源数量(3类资源,空格隔开)\n");
printf("Available:");
for (int j = 0; j < m; j++)
{
available[j] = rand() % 10;
}
while (safety(m, n, allocation, available, need, Work, Finish, work, WaddA, p) == false)
{
for (int i = 0; i < m; i++)
{
available[i] = rand() % 10;
}
}
for (int j = 0; j < m; j++)
{
printf("%d\t",available[j]);
}
}
void Banker(int m, int n, int allocation[][3], int *available, int need[][3], int *Work, bool *Finish, int work[][3], int WaddA[][3], int *p,int Request[][3]) //银行家算法
{
printf("输入请求资源的进程号:\n");
int pid;
scanf("%d",&pid);
printf("\n输入请求资源的数量(3类资源,空格隔开):");
for (int j = 0; j < m; j++)
{
scanf("%d",&Request[pid][j]);
}
for (int j = 0; j < m; j++)
{
if (Request[pid][j] > need[pid][j])
{
printf("请求资源数量大于Need数量,分配失败!\n");
return;
}
else
{
if (Request[pid][j] > available[j])
{
printf("请求资源数量大于Available数量,分配失败!\n");
return;
}
}
}
for (int j = 0; j < m; j++)
{
available[j] = available[j] - Request[pid][j];
allocation[pid][j] = allocation[pid][j] + Request[pid][j];
need[pid][j] = need[pid][j] - Request[pid][j];
}
bool safe = safety(m,n,allocation,available,need, Work,Finish, work, WaddA,p);
if (safe == true)
{
print_sequence(m,n,allocation,need, p, work, WaddA, Finish);
printf("请求成功!\n");
}
else
{
printf("系统进入不安全状态,请求失败!\n");
for (int j = 0; j < m; j++)
{
available[j] = available[j] + Request[pid][j];
allocation[pid][j] = allocation[pid][j] - Request[pid][j];
need[pid][j] = need[pid][j] + Request[pid][j];
}
}
}
int main(int argc,char*argv[])
{
srand((unsigned int)time(NULL));
int m,n;
m=3;
printf("默认资源总类数m: %d",m);
printf("\n请输入模拟的进程数:");
scanf("%d",&n);
int Max[n][m];
printf("\n随机生成最大需求矩阵......");
for (int i = 0; i < n; i++)
{
for (int j = 0; j < m; j++)
{
Max[i][j] = rand() % 10;
}
}
int allocation[n][m];
printf("\n随机生成已分配资源矩阵......");
for (int i = 0; i < n; i++)
{
for (int j = 0; j < m; j++)
{
allocation[i][j] = rand() % 10;
while (allocation[i][j] > Max[i][j])
{
allocation[i][j] = rand() % 10;
}
}
}
int need[n][m];
for (int i = 0; i < n; i++)
{
for (int j = 0; j < m; j++)
{
need[i][j] = Max[i][j] - allocation[i][j];
}
}
int Request[n][m]; //请求
int Work[m]; //工作向量
bool Finish[n];
int WaddA[n][m]; //记录Work+Allocation
int p[n];
int work[n][m];
int available[m]; //可利用资源向量,此为默认值
printf("\n随机生成模拟可利用资源向量......");
for (int i = 0; i < m; i++)
{
available[i] = rand() % 10;
}
while (safety(m, n, allocation, available, need, Work, Finish, work, WaddA, p) == false)
{
for (int i = 0; i < m; i++)
{
available[i] = rand() % 10;
}
}
//int work[n][m]; //记录work
int flag = 1;
while (1)
{
int sel;
menu();
scanf("%d",&sel);
switch (sel)
{
case 1:
init2(m,n,Max,allocation,available,need, Work, Finish, work, WaddA, p);
break;
case 2:
print(m,n,Max,allocation,available,need);
break;
case 3:
Banker(m,n,allocation,available,need, Work,Finish,work,WaddA,p,Request);
break;
case 4:
flag = 0;
break;
}
if (flag == 0)
break;
}
return 0;
}
结果:
思考题:
1、如何设计程序的输入模块才能满足实验要求,请举例说明;
答:在输入模块中,max[n][m]和allocation[n][m],available[m]是系统中三个需要随机赋值的矩阵或向量。在设计程序时,进程数是随意,可以自己输入,而资源总类数是固定的,因为,当一个某一个环境确定时,比如一台电脑完成时,其内部的各种资源已经确定,故而程序中的资源总类数是一个常量值,为了便于观察,默认为3。
为了保证系统模拟的真实性,在进行随机赋值的时候,Max和allocation两个矩阵随机赋值,根据规定,allocation必须小于或等于Max,而available的赋值是建立在系统处于安全状态下的赋值,也就是说赋值后,或者初始化后,系统必须处于安全状态,否则没有意义,所以随机赋值需要在这两个条件下进行。
2.银行家算法在实现过程中必须注意哪些资源分配细节才能避免死锁?
答:当收到资源请求后,
1)判断是否低于最大需求量,判断是否有足够的资源
2)再分配除去资源前需要先假设预测一下,再分配资源后,系统是否还处于安全状态,若仍处于安全状态,则请求允许,反之则不行。