银行家算法模拟
我们可以把操作系统看作是银行家,操作系统管理的资源相当于银行家管理的资金,进程向操作系统请求分配资源相当于用户向银行家贷款。
为保证资金的安全,银行家规定:
(1) 当一个顾客对资金的最大需求量不超过银行家现有的资金时就可接纳该顾客;
(2) 顾客可以分期贷款,但贷款的总数不能超过最大需求量;
(3) 当银行家现有的资金不能满足顾客尚需的贷款数额时,对顾客的贷款可推迟支付,但总能使顾客在有限的时间里得到贷款;
(4) 当顾客得到所需的全部资金后,一定能在有限的时间里归还所有的资金.
银行家算法数据结构
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。
4)需求矩阵Need。
这也是一个n×m的矩阵,用以表示每一个进程尚需的各类资源数。如果Need[i,j]=K,则表示进程i还需要Rj类资源K个,方能完成其任务。
Need[i,j]=Max[i,j]-Allocation[i,j]
算法 的实现
一、初始化
由用户输入数据,分别对可利用资源向量矩阵AVAILABLE 、 最大需求矩阵MAX 、分配矩阵ALLOCATION、 需求矩阵NEED 赋值。
二、银行家算法
在避免死锁的方法中,所施加的限制条件较弱,有可能获得令人满意的系统性能。在该方法中把系统的状态分为安全状态和不安全状态,只要能使系统始终都处于安全状态,便可以避免发生死锁。
银行家算法的基本思想是分配资源之前, 判断系统是否是安全的; 若是, 才分配。它是最具有 代表性的避免死锁的算法。
设进程cusneed 提出请求REQUEST [i] ,则银行家算法按如下规则进行判断。
(1) 如果REQUEST [cusneed] [i]<= NEED[cusneed][i] ,则转(2) ;否则,出错。
(2) 如果REQUEST [cusneed] [i]<= AVAILABLE[cusneed][i] ,则转(3) ;否则,出错。
(3) 系统试探分配资源,修改相关数据:
AVAILABLE[i]-=REQUEST[cusneed][i];
ALLOCATION[cusneed][i]+=REQUEST[cusneed][i];
NEED[cusneed][i]-=REQUEST[cusneed][i];
(4) 系统执行安全性检查,如安全,则分配成立;否则试探险性分配作废,系统恢复 原状, 进程等待。
三、安全性检查算法
(1) 设置两个工作向量Work=AVAILABLE;FINISH
(2) 从进程集合中找到一个满足下述条件的进 程,
FINISH==false;
NEED<=Work;
如找到,执行(3) ; 否则,执行(4)
(3) 设进程获得资源,可顺利执行,直至完 成,从而释放资源。
Work+=ALLOCATION;
Finish=true;
GOTO 2
(4) 如所有的进程Finish= true ,则表 示安全;否则系统不安全。
操作系统安全状态和不安全状态:
安全序列是指一个进程序列{P1,…,Pn}是安全的,如果对于每一个进程Pi(1≤i≤n),它以后尚需要的资源量不超过系统当前剩余资源量与所有进程Pj (j < i )当前占有资源
量之和。
如果存在一个由系统中所有进程构成的安全序列P1,…,Pn,则系统处于安全状态。安全状态一定是没有死锁发生。
不存在一个安全序列。不安全状态不一定导致死锁。
各算法流程图
初始化算法流程图:
银行家算法流程图:
安全性算法流程 图:
package Banker;
import java.util.Scanner;
public class Banker {
/**
* @param args
*/
int MAXPROCESS =50; /*最大进程数*/
int MAXRESOURCE =100; /*最大资源数*/
int m,n; /*m个进程,n个资源*/
int[][] MAX;
int[][] ALLOCATION ;
int[][] NEED ;
int[] AVAILABLE ;
int[][] REQUEST ;
int[] p ;
boolean[] FINISH ;
public void Init() /*初始化算法*/
{
int i,j;
Scanner in = new Scanner(System.in);
System.out.println("请输入进程的数目:");
m=in.nextInt();
System.out.println("请输入资源的种类:");
n=in.nextInt();
System.out.println("请输入每个进程最多所需的各资源数,按照"+m+"x"+n+"矩 阵输入");
MAX =new int[m][n];
for(i=0;i<m;i++) {
for(j=0;j<n;j++) {
MAX[i][j]=in.nextInt();
}}
System.out.println("请输入每个进程已分配的各资源数,也按照"+m+"x"+n+"矩 阵输入");
ALLOCATION=new int[m][n];
NEED=new int[m][n];
AVAILABLE=new int[n];
REQUEST=new int[m][n];
p=new int[m];
FINISH=new boolean[m];
for(i=0;i<m;i++)
{
for(j=0;j<n;j++)
{
ALLOCATION[i][j]=in.nextInt();
NEED[i][j]=MAX[i][j]-ALLOCATION[i][j];
if(NEED[i][j]<0)
{
System.out.println("您输入的第"+i+1+"个进程所拥有的第"+j+1+"个资源数 错误,请重新输入:");
j--;
continue;
}
}
}
System.out.println("请输入各个资源现有的数目:");
for(i=0;i<n;i++)
{
AVAILABLE[i]=in.nextInt();
}
}
void Bank() /*银行家算法*/
{
Scanner in = new Scanner(System.in);
int i,cusneed,flag = 0;
char again;
while(true)
{
showdata(n,m);////////////////////////////////////////////////////////////////////
System.out.println("请输入要申请资源的进程号(注:第1个进程号为0,依次类推)");
int cusneed1=in.nextInt();
if (cusneed1 > m)
{
System.out.println("没有该进程,请重新输入");
}
System.out.println("请输入进程所请求的各资源的数量");
for(i=0;i<n;i++)
{
REQUEST[cusneed1][i]=in.nextInt();
}
for(i=0;i<n;i++)
{
if(REQUEST[cusneed1][i]>NEED[cusneed1][i])//如果用户选择的线程的第i个资源请求数>该线程该资源所需的数量
{
System.out.println("您输入的请求数超过进程的需求量!请重新输入!");
}
if(REQUEST[cusneed1][i]>AVAILABLE[i])//如果用户选择的线程的第i个资源请求数>系统现有的第i个资源的数量
{
System.out.println("您输入的请求数超过系统有的资源数!请重新输入!");
}
}
for(i=0;i<n;i++)//如果请求合理,那么下面
{
AVAILABLE[i]-=REQUEST[cusneed1][i];//系统可用资源减去申请了的
ALLOCATION[cusneed1][i]+=REQUEST[cusneed1][i];//线程被分配的资源加上已申请了的
NEED[cusneed1][i]-=REQUEST[cusneed1][i];//线程还需要的资源减去已申请得到的
}
if(Safe())//AVAILABLE ALLOCATION NEED变动之后,是否会导致不安全
{
System.out.println("同意分配请求!");
}
else
{
System.out.println("您的请求被拒绝!");
for(i=0;i<n;i++)
{
AVAILABLE[i]+=REQUEST[cusneed1][i];
ALLOCATION[cusneed1][i]-=REQUEST[cusneed1][i];
NEED[cusneed1][i]+=REQUEST[cusneed1][i];
}
}
for (i=0;i<n;i++)
{
if (NEED[cusneed1][i] <= 0)
{
flag++;
}
}
if (flag == n)//如果该进程各资源都已满足条件,则释放资源
{
for (i=0;i<n;i++)
{
AVAILABLE[i] += ALLOCATION[cusneed1][i];
ALLOCATION[cusneed1][i] = 0;
NEED[cusneed1][i] = 0;
}
System.out.println("线程"+cusneed1+" 占有的资源被释放!");
flag = 0;
}
for(i=0;i<m;i++)//分配好了以后将进程的标识FINISH改成false
{
FINISH[i]=false;
}
System.out.println("您还想再次请求分配吗?是请按y/Y,否请按其它键");
again=(char) in.nextInt();
if(again=='y'||again=='Y')
{
continue;
}
break;
}
}
public Boolean Safe() /*安全性算法*/
{
int i,j,k,l=0;
int[] Work =new int[MAXRESOURCE]; /*工作数组*/
for(i=0;i<n;i++)
Work[i]=AVAILABLE[i];
for(i=0;i<m;i++)
{
FINISH[i]=false;//FINISH记录每个进程是否安全
}
for(i=0;i<m;i++)
{
for(j=0;j<n;j++)//循环查找第i个进程需要的各个资源数 是否 超过系统现有的对应的资源数
{
if(NEED[i][j]>Work[j])//第i个进程需要的第j个资源数 > 系统现有的第j个资源数
{
break;
}
}
if(j==n)//如果第i个进程所需的各个资源数都没有超过系统现有的对应资源数
{
FINISH[i]=true;//给该进程的FINISH标记为true
for(k=0;k<n;k++)
{
Work[k]+=ALLOCATION[i][k];//将Work赋值为 第i个进程各个已分配资源数+系统现有的对应资源数(因为当改进程全部资源数都满足时线程结束并将资源返还给系统)
}
p[l++]=i;//记录进程号
}
else//如果超过继续循环下一个进程
{
continue;
}
if(l==m)//当所有进程都能够被满足运行时
{
System.out.println("系统是安全的");
System.out.println("安全序列:");
for(i=0;i<l;i++)//改了146行的i值,显示资源分配给进程的顺序
{
System.out.println(p[i]);
if(i!=l-1)
{
System.out.println("-->");
}
}
System.out.println("");
return true;
}
}//for循环
System.out.println("系统是不安全的");
return false;
}
void showdata(int n,int m) //显示
{
int i,j;
System.out.println();
System.out.println("-------------------------------------------------------------");
System.out.println("系统可用的资源数为: ");
for (j=0;j<n;j++)
System.out.println(" "+AVAILABLE[j]);
System.out.println();
System.out.println("各进程还需要的资源量:");
for (i=0;i<m;i++)
{
System.out.println(" 进程"+i+":");
for (j=0;j<n;j++)
System.out.println(" "+NEED[i][j]);
}
System.out.println("各进程已经得到的资源量: ");
for (i=0;i<m;i++)
{
System.out.println(" 进程"+i+":");
for (j=0;j<n;j++)
System.out.println(" "+ALLOCATION[i][j]);
System.out.println();
}
}
public static void main(String[] args) {
// TODO Auto-generated method stub
Banker Bank=new Banker();
Bank.Init();
Bank.Safe();
Bank.Bank();
}