银行家算法是一种用于避免死锁的算法,特别适用于资源分配问题。在多道程序设计中,多个进程需要共享有限的资源,如内存、CPU时间片、I/O设备等。银行家算法通过在分配资源时进行安全性检查,确保系统不会进入死锁状态。
一、银行家算法的基本概念
进程(Process): 请求资源的主体。资源类型(Resource Types): 各类资源,如CPU、内存等。最大需求矩阵(Max): 每个进程对每种资源的最大需求。已分配矩阵(Allocation): 当前已经分配给每个进程的资源。需求矩阵(Need) 每个进程还需要的资源,Need[i][j] = Max[i][j] - Allocation[i][j]
。可用资源向量(Available): 当前可供分配的资源总量。工作向量(Work): 当前可用的资源,在算法执行中用来模拟资源分配过程。完成向量(Finish): 标记进程是否完成,初始值为 false
。 二、代码
运行效果
完整代码
#include <malloc.h> #include <stdio.h> #include <string.h> #include <windows.h> #define M 3 //资源种类 #define N 5 //作业数量 #define False 0 #define True 1 char name[N];//资源的名称 int Request[N]={0}; //进程的请求资源向量 int Resource[M];//各资源总数 int Max[N][M];//各进程对各类资源的最大需求 int Allocation[N][M];//各进程已分配资源 int Need[N][M];//各进程还需要资源 int Available[M];//系统可用资源向量 int Work[M];//存放系统可提供使用资源,工作向量 int Finish[N];//判断安全性标志 int temp[N];//存放安全序列的下标序列 list void initial() //创建初始状态:先输入 Resource、Max和 Allocation,再计算出 Need、Available。 { int i,j; printf("请输入3种资源的总数量:\n"); for(i=0;i<M;i++) { scanf("%d",&Resource[i]); Available[i]=Resource[i]; // 此时,可利用资源数=总资源数 } printf("请输入5个进程分别对M种资源的最大需求量:\n"); for(j=0;j<N;j++) for(i=0;i<M;i++) scanf("%d",&Max[j][i]); // 最大需求量 printf("请输入N个进程获得M种资源的数量:\n"); for(j=0;j<N;j++) for(i=0;i<M;i++) scanf("%d",&Allocation[j][i]); // 已分配各资源数 for(j=0;j<N;j++) for(i=0;i<M;i++) Need[j][i]=Max[j][i]-Allocation[j][i]; // 还需资源数 for(j=0;j<M;j++) for(i=0;i<N;i++) Available[j]=Available[j]-Allocation[i][j]; // 还可利用资源数 } void printState() //输出当前的状态表 { int i; printf("状态表:\n|Process |Max |Allocation |Need |Available | \n"); printf("\t | %c %c %c| %c %c %c| %c %c %c| %c %c %c| \n",name[0],name[1],name[2],name[0],name[1],name[2],name[0],name[1],name[2],name[0],name[1],name[2]); for(i=0;i<N;i++) { if(i==0) printf("|P%-11d|%4d%4d%4d|%4d%4d%4d|%4d%4d%4d|%4d%4d%4d|\n",i,Max[i][0],Max[i][1],Max[i][2],Allocation[i][0],Allocation[i][1],Allocation[i][2],Need[i][0],Need[i][1],Need[i][2],Available[0],Available[1],Available[2]); // 输出11位整型数, 不够11位按左对齐 else printf("|P%-11d|%4d%4d%4d|%4d%4d%4d|%4d%4d%4d| |\n",i,Max[i][0],Max[i][1],Max[i][2],Allocation[i][0],Allocation[i][1],Allocation[i][2],Need[i][0],Need[i][1],Need[i][2]); } } int isfinish() //返回同时满足两个条件{①Finish[i]=false; ②Need[i][j]≤Work[j]}的进程下标 i(修改Finish[i]=true),否则返回-1。 需求≤可利用{ int i,j,count; for(i=0;i<N;i++) // 计算每个进程finish值 { for(j=0,count=0;j<M;j++) if(Finish[i]==0 && Need[i][j]<=Work[j]) // 仅暂时未分配成功的进程的资源进行判断并计数 { count++; } if(count==3) // 表示进程中三个资源均可被分配 { for(j=0;j<M;j++) Work[j]+=Allocation[i][j]; // 分配 Finish[i]=1; // 进程可结束 return i; // 返回新分配资源的进程号 } } return -1; } int issafe() //判定当前状态是否为安全状态 (返回 true 或 false),把安全序列的下标放入 List[N]数组。 { int i,a,count=0; for(i=0;i<M;i++) Work[i]=Available[i]; // 此时,各资源现可利用数=剩余可利用的各资源数 for(i=0;i<N;i++) Finish[i]=0; // 初始化finish[ ]数组,均设为false for(i=0;i<N;i++) { a=isfinish(); if(a!=-1) // 表示可结束的安全序列下标 { temp[i]=a; count++; // 记录可安全结束的进程数量 } } if(count==5) return 1; // 存在安全序列 else return 0; // 不存在安全序列 } void printList( ) //输出安全序列表|Process |Work |Need |Allocation |Work+Alloc |Finish | { int i,j; printf("\n安全序列表如下:\n|Process |Work |Need |Allocation |Work+Alloc |Finish |\n"); printf("\t | %c %c %c| %c %c %c| %c %c %c| %c %c %c|\n",name[0],name[1],name[2],name[0],name[1],name[2],name[0],name[1],name[2],name[0],name[1],name[2]); for(j=0;j<M;j++) { Work[j]=Available[j]; } for(i=0;i<N;i++) { printf("|P%-11d|%4d%4d%4d|%4d%4d%4d|%4d%4d%4d|%4d%4d%4d|true\n",temp[i],Work[0],Work[1],Work[2],Need[temp[i]][0],Need[temp[i]][1],Need[temp[i]][2],Allocation[temp[i]][0],Allocation[temp[i]][1],Allocation[temp[i]][2],Work[0]+Allocation[temp[i]][0],Work[1]+Allocation[temp[i]][1],Work[2]+Allocation[temp[i]][2]); for(j=0;j<M;j++) Work[j]+=Allocation[temp[i]][j]; } } void reqresource(int i, int Request[M]) //表示第 i个进程请求 M类资源 request[M] { int flag,count1,count2; int j; //Step1: 判断条件 Request[j]≤Need[i][j] for(j=0,count1=0;j<M;j++) if(Request[j]<=Need[i][j]) count1++; //Step2: 判断条件 Request[j]≤Available[j] for(j=0,count2=0;j<M;j++) if(Request[j]<=Available[j]) count2++; if(count2!=3) printf("\n尚无足够的资源,第%d个进程堵塞。\n",i); // 越界 //Step3: 预先分配 if(count2==3 && count1==3) // 未越界 { for(j=0;j<M;j++) { Available[j]=Available[j]-Request[j]; Allocation[i][j]=Allocation[i][j]+Request[j]; Need[i][j]=Need[i][j]-Request[j]; } // 预先更新进程i的Available,Allocation,Need状态表 if(issafe()==0) { printf("\n不存在安全序列,不是安全状态。\n"); for(j=0;j<M;j++) { Available[j]=Available[j]+Request[j]; Allocation[i][j]=Allocation[i][j]-Request[j]; Need[i][j]=Need[i][j]+Request[j]; } // 恢复进程i的Available,Allocation,Need状态表 } else { printf("\n是安全序列分配成功!\n"); printList(); } } //Step4:检测是否为安全状态} int main() { int reqid=-1,j; initial(); // 初始化 for(int a=0;a<M;a++){ name[a]=a+65; } // 定义资源名称A,B,C printState(); // 输出状态表 if(issafe()==0) // 判断安全状态 { printf("初始状态不安全!\n"); } else { printf("\n初始状态是安全的!\n"); printList(); // 输出安全序列状态表 printf("\n"); printf("请输入请求资源进程号(如 1,2,3):"); scanf("%d",&reqid); // 输入请求资源id号 while(reqid>=0 && reqid<N) // 判断输入进程 id是否合法 { printf("请输入请求资源:"); for(j=0;j<M;j++) { scanf("%d",&Request[j]); } // 输入请求资源进程的各资源请求数 reqresource(reqid, Request); // 进程reqid请求Request[M]资源 printState(); printf("\n"); printf("请输入请求资源进程号(如 1,2,3):"); scanf("%d",&reqid); } } return 0; }