一、实验目的
(1) 进一步了解进程的并发执行。
(2) 加强对进程死锁的理解,理解安全状态与不安全状态的概念。
(3) 掌握使用银行家算法避免死锁问题。
二、总体设计
2.1实验基本知识及原理
(1)基本概念
死锁:多个进程在执行过程中,因为竞争资源会造成相互等待的局面。如果没有外力作用,这些进程将永远无法向前推进。此时称系统处于死锁状态或者系统产生了死锁。
安全序列:系统按某种顺序并发进程,并使它们都能达到获得最大资源而顺序完成的序列为安全序列。
安全状态:能找到安全序列的状态称为安全状态,安全状态不会导致死锁。
不安全状态:在当前状态下不存在安全序列,则系统处于不安全状态。
(2)银行家算法
银行家算法顾名思义是来源于银行的借贷业务,一定数量的本金要满足多个客户的借贷周转,为了防止银行家资金无法周转而倒闭,对每一笔贷款,必须考察其是否能限期归还。
在操作系统中研究资源分配策略时也有类似问题,系统中有限的资源要供多个进程使用,必须保证得到的资源的进程能在有限的时间内归还资源,以供其它进程使用资源。如果资源分配不当,就会发生进程循环等待资源,则进程都无法继续执行下去的死锁现象。
当一进程提出资源申请时,银行家算法执行下列步骤以决定是否向其分配资源:
1)检查该进程所需要的资源是否已超过它所宣布的最大值。
2)检查系统当前是否有足够资源满足该进程的请求。
3)系统试探着将资源分配给该进程,得到一个新状态。
4)执行安全性算法,若该新状态是安全的,则分配完成;若新状态是不安全的,则恢复原状态,阻塞该进程。
2.2 实验内容
本实验的内容是要通过编写和调试一个模拟系统动态分配资源的银行家算法程序,有效地避免死锁发生。具体要求如下:
(1) 初始化时让系统拥有一定的资源;
(2) 用键盘输入的方式允许进程动态申请资源;
(3) 如果试探分配后系统处于安全状态,则修改系统的资源分配情况,正式分配资源;
(4) 如果试探分配后系统处于不安全状态,则提示不能满足请求,恢复原状态并阻塞该进程。
三、详细设计
3.1 银行家算法中的数据结构与流程图
(1)数据结构:
资源总量向量 Resource, m 维,表示 m 种资源的总量。
可用资源向量 Available, m 维,表示未分配的各种可用资源数量。
需求矩阵 Claim, n*m 矩阵,表示 n 个进程对 m 类资源的最大需求。
分配矩阵 Allocation , n*m 矩阵,表示 n 个进程已分配的各种资源数。
(2)算法流程图: 请补充画出算法流程图。
3.2 银行家算法编程实现
#include "string.h" #include "iostream" using namespace std; #define FALSE 0 #define TRUE 1 #define W 10 #define R 20 int M=4 ; //总进程数 int N=3 ; //资源种类 int ALL_RESOURCE[3]={9,3,6};//各种资源的数目总和 int MAX[4][3]={{3,2,2},{6,1,3},{3,1,4},{4,2,2}}; //M个进程对N类资源最大资源需求量 int AVAILABLE[R]; //系统可用资源数 int ALLOCATION[4][3]={{1,0,0},{6,1,2},{2,1,1},{0,0,2}}; //M个进程已经得到N类资源的资源量 int NEED[W][R]; //M个进程还需要N类资源的资源量 int Request[R]; //请求资源个数 void showdata() //函数showdata,输出资源分配情况 { int i,j; cout<<"各种资源的总数量(all):"; cout<<" ["; for (j=0;j<N;j++)cout<<" "<<ALL_RESOURCE[j]; cout<<" ]"; cout<<endl<<endl; cout<<"系统目前各种资源可用的数为(available):"; cout<<" ["; for (j=0;j<N;j++)cout<<" "<<AVAILABLE[j]; cout<<" ]"; cout<<endl<<endl; cout<<" 各进程已经得到的资源量(allocation): "<<endl<<endl; cout<<" 资源0"<<" 资源1"<<" 资源2"<<endl; for (i=0;i<M;i++) { cout<<"进程p"<<i<<": "; for (j=0;j<N;j++)cout<<ALLOCATION[i][j]<<" "; cout<<endl; } cout<<endl; cout<<" 各进程还需要的资源量(need):"<<endl<<endl; cout<<" 资源0"<<" 资源1"<<" 资源2"<<endl; for (i=0;i<M;i++) for (i=0;i<M;i++) { cout<<"进程p"<<i<<": "; for (j=0;j<N;j++)cout<<NEED[i][j]<<" ";; cout<<endl; } cout<<endl; } void changdata(int k) //分配资源 { int j; for (j=0;j<N;j++) { AVAILABLE[j]=AVAILABLE[j]-Request[j]; ALLOCATION[k][j]=ALLOCATION[k][j]+Request[j]; NEED[k][j]=NEED[k][j]-Request[j];}} void rstordata(int k) //恢复现场 { int j; for (j=0;j<N;j++) { AVAILABLE[j]=AVAILABLE[j]+Request[j]; ALLOCATION[k][j]=ALLOCATION[k][j]-Request[j]; NEED[k][j]=NEED[k][j]+Request[j];}} int chkerr(int s) //函数chkerr,检查是否安全 { int WORK,FINISH[W]; int i,j,k=0; for(i=0;i<M;i++)FINISH[i]=FALSE; for(j=0;j<N;j++) { WORK=AVAILABLE[j]; i=s; do { if(FINISH[i]==FALSE&&NEED[i][j]<=WORK) { WORK=WORK+ALLOCATION[i][j]; FINISH[i]=TRUE; i=0; } else { i++; } }while(i<M); for(i=0;i<M;i++) if(FINISH[i]==FALSE) { cout<<endl; cout<<" 系统不安全!!! 本次资源申请不成功!!!"<<endl; cout<<endl; return 1; } } cout<<endl; cout<<" 经安全性检查,系统安全,本次分配成功。"<<endl; cout<<endl; return 0; } void bank() //银行家算法主体 { int i=0,j=0; char flag='Y'; while(flag=='Y'||flag=='y') { i=-1; while(i<0||i>=M) { cout<<" 请输入需申请资源的进程号(从P0到P"<<M-1<<",否则重输入!):"; cout<<"P";cin>>i; if(i<0||i>=M)cout<<" 输入的进程号不存在,重新输入!"<<endl; } cout<<" 请输入进程P"<<i<<"申请的资源数:"<<endl; for (j=0;j<N;j++) { cout<<" 资源"<<j<<": "; cin>>Request[j]; if(Request[j]>NEED[i][j]) //若请求的资源数大于进程还需要i类资源的资源量j { cout<<" 进程P"<<i<<"申请的资源数大于进程P"<<i<<"还需要"<<j<<"类资源的资源量!"; cout<<"申请不合理,出错!请重新选择!"<<endl<<endl; flag='N'; break; } else { if(Request[j]>AVAILABLE[j]) //若请求的资源数大于可用资源数 { cout<<" 进程P"<<i<<"申请的资源数大于系统可用"<<j<<"类资源的资源量!"; cout<<"申请不合理,出错!请重新选择!"<<endl<<endl; flag='N'; break; } } } if(flag=='Y'||flag=='y') { changdata(i); //调用changdata(i)函数,改变资源数 if(chkerr(i)) //若系统安全 { rstordata(i); //调用rstordata(i)函数,恢复资源数 showdata(); //输出资源分配情况 } else //若系统不安全 showdata(); //输出资源分配情况 } else //若flag=N||flag=n showdata(); cout<<endl; cout<<" 是否继续银行家算法演示,按'Y'或'y'键继续,按'N'或'n'键退出演示: "; cin>>flag; } } //主函数 void main() { int i=0,j=0,p; //初始化资源数量 for (j=0;j<N;j++) { p=ALL_RESOURCE[j]; for (i=0;i<M;i++) { p=p-ALLOCATION[i][j];//减去已经被占据的资源 AVAILABLE[j]=p; if(AVAILABLE[j]<0) AVAILABLE[j]=0; } } for (i=0;i<M;i++) for(j=0;j<N;j++) NEED[i][j]=MAX[i][j]-ALLOCATION[i][j]; showdata(); bank(); }
四、实验结果与分析
银行家算法是接收一个进程对资源的申请,分配时判断是否存在一个安全序列使得进程间不会发生死锁,若不存在安全序列(一定会发生死锁)则让该进程进入等待不给予分配资源。
五、小结与心得体会
通过对银行家算法的实现,让我对银行家算法有利更深刻的的了解,用银行家算法避免死锁。在编程实现过程中,找到许多对银行家算法的疏忽,有许多细节问题需要注意,同时对死锁预防的理论知识掌握更加透彻。