问题描述:
死锁会引起计算机工作僵死,因此操作系统中必须防止。本实验的目的在于让学生独立的使用高级语言编写和调试一个系统动态分配资源的简单模拟程序,了解死锁产生的条件和原因,并采用银行家算法有效地防止死锁的发生,以加深对课堂上所讲授的知识的理解。
数据结构:
1. 可利用资源向量Available ,它是一个含有m个元素的数组,其中的每一个元素代表一类可利用的资源的数目,其初始值是系统中所配置的该类全部可用资源数目。其数值随该类资源的分配和回收而动态地改变。如果Available(j)=k,标是系统中现有Rj类资源k个。
2. 最大需求矩阵Max,这是一个n×m的矩阵,它定义了系统中n个进程中的每一个进程对m类资源的最大需求。如果Max(i,j)=k,表示进程i需要Rj类资源的最大数目为k。
3. 分配矩阵Allocation,这是一个n×m的矩阵,它定义了系统中的每类资源当前一分配到每一个进程的资源数。如果Allocation(i,j)=k,表示进程i当前已经分到Rj类资源的数目为k。Allocation i表示进程i的分配向量,有矩阵Allocation的第i行构成。
4. 需求矩阵Need,这是一个n×m的矩阵,用以表示每个进程还需要的各类资源的数目。如果Need(i,j)=k,表示进程i还需要Rj类资源k个,才能完成其任务。Need i表示进程i的需求向量,由矩阵Need的第i行构成。
上述三个矩阵间存在关系:Need(i,j)=Max(i,j)-Allocation(i,j);
程序流程图
编程思路:
银行家算法的核心就是该分配的安全性问题。安全性问题的主要是看其是否能够在分配给一进程所申请的资源之后,是否能够找到一个安全序列即所有进程都能执行完的资源分配顺序,若能则该申请安全不会引发死锁,将系统资源按进程所申请的进行分配。若不能则该申请不安全,可能会引发死锁,系统就拒绝进程的资源申请。重复上述操作直至所有的进程都执行完毕。
测试用例:
实验代码(java)
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner scanner=new Scanner(System.in);
System.out.println("\t请输入CPU有多少种资源");
int M=scanner.nextInt(); //资源种类的数目为M
int available[]=new int[M]; //系统中每种资源的数量
// int request[][]=new int[][]; //请求数组 进程i请求j类资源的数量
System.out.println("\t请各类输入资源的总量\t");
System.out.println("\t资源名种类\t资源数量 ");
for(int i=0;i<M;i++)
{
System.out.print("\t"+i+"\t");
available[i]=scanner.nextInt();
//System.out.println();
}
System.out.println("\t资源初始化完成");
System.out.println("\t请输入进程数");
int N=scanner.nextInt(); //进程数目为N
int max[][]=new int[N][M]; //max[i][j] 进程i需要j类资源的数量
int need[][]=new int[N][M]; //need[i][j] 进程i还需要j类资源的数量
int allocation[][]=new int[N][M]; //allocation[i][j] 进程i已经获得j类资源的数量
for(int i=0;i<N;i++)
{
System.out.println("\t请输入进程"+i+"对各类资源的需求数目");
System.out.println("\t资源名种类\t需求资源数目 ");
for(int j=0;j<M;j++)
{
System.out.print("\t"+j+"\t");
max[i][j]=scanner.nextInt();
//System.out.println();
while(max[i][j]>available[j])
{
System.out.println("\t警告!!!程序资源需求超过系统资源总量。"+available[i]);
System.out.println("\t请重新输入"+j+"类资源需求数目");
max[i][j]=scanner.nextInt();
}
//available[i]=available[i]-max[i][j];
}
}
for(int i=0;i<N;i++)
{
for(int j=0;j<M;j++)
{
need[i][j]=max[i][j];
}
}
for(int i=0;i<N;i++)
{
System.out.println("\t请输入进程"+i+"已经获得的资源数");
System.out.println("\t资源名种类\t已经分配资源数目 ");
for(int j=0;j<M;j++)
{
System.out.print("\t"+j+"\t");
allocation[i][j]=scanner.nextInt();
// System.out.println();
while(allocation[i][j]>Math.min(need[i][j], available[j]))
{
System.out.println("\t警告!!!程序已分配资源大于需求资源数或大于系统可分配资源数。"+need[i][j]);
System.out.println("\t请重新输入"+j+"类资源已经分配数目");
allocation[i][j]=scanner.nextInt();
}
}
}
for(int i=0;i<N;i++)
{
for(int j=0;j<M;j++)
{
need[i][j]=max[i][j]-allocation[i][j];
available[j]-=allocation[i][j];
}
}
System.out.println("\t进程资源需求初始化完成\t");
diaodu(N,M,need,allocation,available);
}
//安全性算法
public static boolean save(int N,int M,int available[],int need[][],int allocation[][])
{
boolean fanhui=false;
// System.out.println("333333333");
int finish[]=new int[N]; //是否进行过该进程是否会死锁 true不会
for(int j=0;j<N;j++)//初始化
{
finish[j]=1;
}
int work[]=new int[M]; //指的是当前CPU能够提供的资源
for(int i=0;i<M;i++)//初始化work
{
work[i]=available[i];
}
boolean flag=true;
int count=0;
while(flag) //整体的循环
{
// System.out.println("444444");
if(count==N)
{
int sum5=0;
for(int x=0;x<N;x++)
{
sum5+=finish[x];
}
if(sum5==0)
{
fanhui=true;
}else {
fanhui=false;
}
flag=false;
}
for(int i=0;i<N;i++) //进程号为i 一次遍历
{
if(finish[i]==1) //未确定
{
boolean flages=true; //若为true则表时当前CPU拥有资源能够满足该进程
for(int s=0;s<M;s++) //资源种类
{
if(need[i][s]>work[s]) //即该进程当前系统无法完成
{
flages=false;
}
}
if(flages) //进程i需求资源CPU能满足
{
for(int s=0;s<M;s++)
{
work[s]+=allocation[i][s]; //资源取回 CPU可用资源增加
}
finish[i]=0; //该进程已经完成分配
}
}
}
count++;
}
return fanhui;
}
public static void diaodu(int N,int M,int need[][],int allocation[][],int available[])
{
Scanner scanner=new Scanner(System.in);
int request[]=new int[M];
boolean flage[]=new boolean[N]; //判断是否已经执行完毕
for(int i=0;i<N;i++)
{
flage[i]=false;
}
//进程调度
while(true)
{
int sum=0;
for(int i=0;i<N;i++)
{
for(int j=0;j<M;j++)
{
sum+=need[i][j];
}
}
if(sum==0)
{
System.out.println("\t调度完毕!");
break;
}
int X=(int)(Math.random()*N); //随机选择调度进程号
while(flage[X])
{
X=(int)(Math.random()*N);
}
System.out.println("\t进程"+X+"还需资源清单");
System.out.println("\t资源名种类\t需求资源数目");
for(int j=0;j<M;j++)
{
System.out.println("\t"+j+"\t"+need[X][j]);
}
System.out.println("\t请输入申请各类资源的数量");
System.out.println("\t资源名种类\t 申请资源数目 ");
for(int m=0;m<M;m++)
{
System.out.print("\t"+m+"\t");
request[m]=scanner.nextInt();
while(need[X][m]<request[m])
{
System.out.println("\t错误的输入!!!申请资源数目超出进程所需数目");
System.out.println("\t请重新输入"+m+"类资源的申请数目");
request[m]=scanner.nextInt();
}
//银行家算法
if(request[m]>available[m])
{
System.out.println("\t系统资源不足!!!"+m+"类资源仅有"+available[m]+"个可分配");
System.out.println("\t进程"+X+"需等待");
request[m]=0;
}else{
// System.out.println("申请成功!!!")
available[m]=available[m]-request[m];
allocation[X][m]+=request[m];
need[X][m]-=request[m];
}
// System.out.println("111111");
}
// System.out.println("22222");
boolean ff=save(N,M,available,need,allocation);
if(ff) //如果安全
{
System.out.println("\t安全");
System.out.println("\t分配完成");
}else {
System.out.println("\t不安全!!! CPU拒绝申请");
for(int n=0;n<M;n++) //各数组回溯
{
available[n]=available[n]+request[n];
allocation[X][n]-=request[n];
need[X][n]+=request[n];
}
}
int needSum=0; //need向量矩阵 即该进程所需资源的总数
for(int i=0;i<M;i++)
{
needSum+=need[X][i];
}
if(needSum==0) //用于判断进程是否已经结束
{
System.out.println("\t进程"+X+"结束");
flage[X]=true;//进程完结 下一次随机将不会有X进程
for(int i=0;i<M;i++) //进行资源回收
{
available[i]+=allocation[X][i];
allocation[X][i]=0;
}
}
}
}
}