银行家算法是操作系统的经典算法之一,用于避免死锁情况的出现。
它最初是为银行设计的(因此得名),通过判断借贷是否安全,然后决定借不借。
在银行中,客户申请贷款的数量是有限的,每个客户在第一次申请贷款时要声明完成该项目所需的最大资金量,在满足所有贷款要求时,客户应及时归还。银行家在客户申请的贷款数量不超过自己拥有的最大值时,都应尽量满足客户的需要。
用在操作系统中,银行家、出借资金、客户,就分别对应操作系统、资源、申请资源的进程。
每一个新进程进入系统时,必须声明需要每种资源的最大数目,其数目不能超过系统所拥有的的资源总量。当进程请求一组资源时,系统必须首先确定是否有足够的资源分配给该进程,若有,再进一步计算在将这些资源分配给进程后,是否会使系统处于不安全状态如果不会才将资源分配给它,否则让进程等待。
为了实现银行家算法,在系统中必须设置这样四个数据结构:
1)Available向量:系统中可利用的资源数目
2)Max矩阵:每个进程对每种资源的最大需求
3)Allocation矩阵:每个进程已分配的各类资源的数目
4)Need矩阵:每个进程还需要的各类资源数
其中三个矩阵间存在下述关系:
Need[i,j] = Max[i,j] - allocation[i, j]
算法逻辑:
设Requesti是进程Pi的请求向量,如果Requesti[j]=K,表示进程Pi需要K个Rj类型的资源。当Pi发出资源请求后,系统按下述步骤进行检查:
(1) 若 Requesti[j] ≤ Need[i,j],转向(2),否则认为出错(因为它所需的资源数目已超过它所宣布的最大值)。
(2) 若 Requesti[j] ≤ Available[j],转向(3),否则须等待(表现为进程Pi受阻)。
(3) 系统尝试把资源分配给进程Pi,并修改下面数据结构中的数值:
Available[j] = Available[j] – Requesti[j]
Allocation[i,j] = Allocation[i,j] + Requesti[j]
Need[i,j] = Need[i,j] –Requesti[j]
(4) 试分配后,执行安全性算法,检查此次分配后系统是否处于安全状态。若安全,才正式分配;否则,此次试分配作废,进程Pi等待。
#include
#include
#define PN 5//进程数
#define RN 4//资源种类数
typedef struct//定义结构体类型pcb
{
char name[3];//进程名,如p0
int max[RN];//最大资源值
int allocation[RN];//已分配资源数
int need[RN];//任需求资源数
}pcb;
struct//定义为结构体类型,方便赋值
{
int flag[PN];//进程检测标志,1时表示已通过
int safes[PN];//存放进程编号,作为安全序列输出
}fs0,fs;//fs0保存初始值,fs用于工作
struct//定义为结构体类型,方便赋值
{
int available[RN];//系统可用资源向量
}av0,av,avx;//av0保存初始值,av和avx用于工作
pcb proc0[PN],proc[PN];//proc0保存初始值,proc用于工作
int request[RN];//进程请求资源向量
void init();//初始化,输入数据
void output(pcb*);//输出数据
void cur_state();//判断系统当前状态
void req_state();//分析进程提出的请求是否可以响应
void back0();//退回至初始值
void back1(int);//退回至分配前
int check(int*);//进程need向量与available向量比较
int banker();//银行家算法
int main()
{
int num;
printf("【银行家算法】\n");
printf("进程数:%d\n",PN);
printf("资源数:%d\n",RN);
printf("=================\n");
init();
output(proc0);//输出初始资源分配情况
printf("【系统当前状态分析】\n");
cur_state();
printf("======================================================\n\n");
printf("选择操作序号(0:结束程序;1:资源请求分析)\n");
printf("输入序号:");
scanf("%d",&num);getchar();
while(1)
{
switch(num)
{
case 1:printf("\n【进程资源请求分析】\n");req_state();break;
default:printf("\n======分析结束!======\n");return 0;
}
printf("\n");
printf("======================================================\n");
printf("\n");
printf("选择操作序号(0:结束程序;1:资源请求分析)\n");
printf("输入序号:");
scanf("%d",&num);getchar();
}
}
void init()
{//初始化
int i,j;
for(i=0;i<PN;i++)
{
printf("\n输入进程名:");
gets(proc0[i].name);
printf("输入max:");
for(j=0;j<RN;j++)
scanf("%d",&proc0[i].max[j]);
printf("输入allocation:");
for(j=0;j<RN;j++)
scanf("%d",&proc0[i].allocation[j]);
for(j=0;j<RN;j++)//计算need
proc0[i].need[j]=proc0[i].max[j]-proc0[i].allocation[j];
fs0.flag[i]=0;//进程标志位置0
fs0.safes[i]=-1;//安全序列置-1
proc[i]=proc0[i];//给工作矩阵proc赋值
getchar();//吸收scanf()产生的回车符
}
printf("\n输入available:");
for(j=0;j<RN;j++)
scanf("%d",&av0.available[j]);
fs=fs0;//给工作单元fs和av赋值
av=av0;
getchar();//吸收scanf()产生的回车符
}
void output(pcb* p)
{//输出资源分配情况,觉得麻烦可以不考虑
int i,j;
printf("\n");
printf("===============================================================================\n");
printf(" 标志位 | 进程名 | 最大值 \t| 已分配 \t| 需求值 \t| 可用数 \n");
printf("-------------------------------------------------------------------------------\n");
for(i=0;i<PN;i++)
{
printf(" %-5d",fs.flag[i]);
printf("|");
printf(" %-5s",p[i].name);
printf("| ");
for(j=0;j<RN;j++)
printf("%-3d",p[i].max[j]);
printf("\t| ");
for(j=0;j<RN;j++)
printf("%-3d",p[i].allocation[j]);
printf("\t| ");
for(j=0;j<RN;j++)
printf("%-3d",p[i].need[j]);
printf("\t| ");
if(i==0)
for(j=0;j<RN;j++)
printf("%-3d",av.available[j]);
printf("\n");
}
printf("===============================================================================\n\n");
}
int banker()
{//银行家算法
int i,j,t=0,k,f;
k=0;//计数器,找到符合条件的进程数
f=1;//标志位,每轮查找标志,f=0时该轮未找到合适进程,查找结束
while(f==1&&k<PN)
{
f=0;//本轮查找标志置0
for(i=0;i<PN;i++)
if(!fs.flag[i]&&check(proc[i].need))
{//找到符合条件的进程
f=1;//本轮查找标志置1
fs.flag[i]=1;//进程标志置1
for(j=0;j<RN;j++)//修改available中的值
av.available[j]+=proc[i].allocation[j];
fs.safes[t]=i;//进程序号i记入safes数组中,作为安全序列输出
t++;k++;
}
}
if(k<PN)return 0;//当k
else return 1;
}
int check(int* p)//p为当前进程的need向量
{//当前进程need向量与available向量比较
int i;
for(i=0;i<RN;i++)
if(p[i]>av.available[i])return 0;//若检测不通过则返回0
return 1;//检测通过
}
void cur_state()
{//检测系统当前状态
int i;
if(banker())
{
printf("分析结果:当前系统处于安全状态,存在安全序列 ");
for(i=0;i<PN;i++)//输出安全序列
printf("p%d",fs.safes[i]);
printf("\n");
}
else
printf("分析结果:当前系统处于不安全状态!请结束程序");
//output(proc);//输出分析后的状态(查看flag和available状况)
fs=fs0;av=av0;//退回至初始状态
printf("\n\n");
}
void req_state()
{//对进程提出的资源请求,判断分配的可行性
int i,j,n;
printf("输入提出请求的进程序号n:p");
scanf("%d",&n);
printf("输入请求资源向量request:");
for(i=0;i<RN;i++)
scanf("%d",&request[i]);
for(i=0;i<RN;i++)//判断请求的合法性
if(request[i]>proc[n].need[i]||request[i]>av.available[i])
{
printf("分析结果:请求不合法,系统不予响应!");
for(j=0;j<RN;j++)
request[j]=0;//清空request
return;
}
for(i=0;i<RN;i++)
{//尝试分配,修改allocation,need和available的值
av.available[i]-=request[i];
proc[n].need[i]-=request[i];
proc[n].allocation[i]+=request[i];
}
avx=av;//avx保存分配后available的值
//output(proc);//输出分配后的资源分布状况
if(banker())//调用银行家算法,寻找安全序列
{
printf("分析结果:当前系统处于安全状态,存在安全序列 ");
for(i=0;i<PN;i++)//输出安全序列
printf("p%d ",fs.safes[i]);
printf("\n");
av=avx;//分析结束,确定资源分配
fs=fs0;//清空标识位flag和安全序列safes
}
else
{
printf("分析结果:不存在安全序列,系统不予响应,进程阻塞!\n");
//output(proc);//输出分析结束后的情况(查看flag和available状况)
back1(n);//取消分配,退回至分配前
printf("已取消分配,退回至分配前\n");
}
printf("\n\n");
printf("输入“y”可退回到初始状态,请选择(y/n)\n");
printf("请输入:");
getchar();//吸收前面的输入所产生的回车符
if(getchar()=='y')
{
back0();
printf("已退回至初始状态\n");
}
}
void back0()
{//恢复至初始值
int i;
fs=fs0;
av=av0;
for(i=0;i<PN;i++)
proc[i]=proc0[i];
}
void back1(int m)//m为提出资源请求的进程序号
{//撤销分配,退回至分配前
int i;
fs=fs0;
for(i=0;i<RN;i++)
{
av.available[i]=avx.available[i]-request[i];
proc[m].need[i]+=request[i];
proc[m].allocation[i]-=request[i];
}
}