银行家算法

死锁避免的经典问题

Posted by TenzT on July 26, 2018

死锁避免设计思想

当进程请求资源时,对进程发出的每一个系统能够满足的自愿申请进行动态检查,并根据检查结果决定是否分配资源。

制约关系

  • 假设进程P和Q同时请求同一个资源,资源总数为M。Q的最大需求量为B,P的最大需求量为A
  • 当已经分配情况的交点处于OXO2Y时,P或Q都能满足
  • 当已经分配情况的交点处于O2O3AX时,能够满足P不能满足Q
  • 当处于BO1O3Y时,能够满足Q不能满足P
  • 当进入O1O2O3时,任意进程都不能满足,认为绝对发生死锁,这是需要避免的

安全状态与安全序列

  • 安全状态:系统中存在一个由所有进程构成的安全序列
  • 安全序列:一个进程序列{P1,…Pn},对于每一个进程,它以后还需要的资源量不超过西戎当前剩余资源量与所有进程Pj(j< i)当前占有资源量(考虑之前的进程占有完后会释放)之和。

典型实现方式(银行家算法)

思路:先假定分配好的情况,再判断是否安全

  • 初始化
    n: 系统进程数量
    m: 资源类数量
    Available ARRAY[1..m] of integer    //可用资源
    Max: ARRAY[1..n, 1..m] of integer   //各进程对各类资源最大需求
    Allocation: ARRAY[1..n, 1..m] of integer    //当前资源分配情况
    Request: ARRAY[1..n, 1..m] of integer       //各进程请求情况
    
  • 假定分配好的状态(以下为简记,只考虑一类资源)
    1. 若Request[i] <= Need[i] 转2. 否则报错
    2. 若Request[i] <= Available 转3. 否则等待
    3. 假设系统分配了资源。则有新状态
      Avaliable -= Request[i]
      Allocation[i] += Request[i];
      Need[i] -= Request[i]
    
  • 安全性检查
    Work: ARRAY[1..m] of integer    //当前剩余资源
    Finish: ARRAY[1..n] of Boolean  //检查进程是否成功
    1. Work = Available; Finish = false
    2. 寻找进程i,满足
      a. Finish[i] == false
      b. Need[i] <= Work
      若不存在,则转4
    3. Work += Work + Allocation; Finish[i]=true;   //模拟Pj释放资源
    4. 若对所有i,Finish[i]==true,则安全,否则不安全
    

Java实现

import java.util.Scanner;

public class Banker {
	final static int NUM_RESOURCES = 100;
	final static int NUM_Thread = 100;
	
	int[] Avaliable = {10, 8, 7};
	int[][] Max = new int[3][3];
	int[][] Allocation = new int[3][3];
	int[][] Need = new int[3][3];
	int[][] Request = new int[3][3];
	int[] Work = new int[3];
	
	int num = 0;//进程编号
	Scanner in = new Scanner(System.in);
	
	public Banker(){}
	
	public void setSystemVariable(){//设置各初始系统变量,并判断是否处于安全状态。
        setMax();
        setAllocation();
        printSystemStatus();
        testSafe();
    }
	
	public void setMax() {//设置Max矩阵
        System.out.println("请设置各进程的最大需求矩阵Max:");
        for (int i = 0; i < 3; i++) {
            System.out.println("请输入进程P" + i + "的最大资源需求量:");
            for (int j = 0; j < 3; j++) {
                Max[i][j] = in.nextInt();
            }
        }
    }
	
	public void setAllocation() {
		System.out.println("请设置各进程分配矩阵Alloction:");
        for (int i = 0; i < 3; i++) {
            System.out.println("请输入进程P" + i + "的分配资源量:");
            for (int j = 0; j < 3; j++) {
                Allocation[i][j] = in.nextInt();
            }
        }
        System.out.println("Available=Available-Alloction.");
        System.out.println("Need=Max-Alloction.");
        for (int i = 0; i < 3; i++) {//设置Alloction矩阵
            for (int j = 0; j < 3; j++) {
            	Avaliable[i] = Avaliable[i] - Allocation[j][i];
            }
        }
        for (int i = 0; i < 3; i++) {//设置Need矩阵
            for (int j = 0; j < 3; j++) {
                Need[i][j] = Max[i][j] - Allocation[i][j];
            }
        }
	}
	public void printSystemStatus() {
		System.out.println("此时资源分配量如下:");
		System.out.println("进程  "+"   Max   "+"   Alloction "+"    Need  "+"     Available ");
		for(int i=0;i<3;i++) {
			System.out.print("P" + i + " ");
			for(int j=0;j<3;j++) {
				System.out.print(Max[i][j] + "  ");
			}
			System.out.print("|  ");
			for(int j=0;j<3;j++) {
				System.out.print(Allocation[i][j] + "  ");
			}
			System.out.print("|  ");
			for(int j=0;j<3;j++) {
				System.out.print(Need[i][j] + "  ");
			}
			System.out.print("|  ");
			if(i==0) {
				for(int j=0;j<3;j++) {
					System.out.print(Avaliable[j] + "  ");
				}				
			}
			System.out.println();
		}
	}
	public void setRequest() {
		System.out.println("输入进程编号");
		num = in.nextInt();
		System.out.println("输入请求资源");
		for(int j=0;j<3;j++) {
			Request[num][j] = in.nextInt();
		}
		System.out.println("即进程P" + num + "对各资源请求Request:(" + Request[num][0] + "," + Request[num][1] + "," + Request[num][2] + ").");
		BankerAlgorithm();
	}
	
	public void BankerAlgorithm() {
		boolean T = true;
		if(Request[num][0] <= Need[num][0] && Request[num][1] <= Need[num][1] && Request[num][2] <= Need[num][2]) {
			if(Request[num][0] <= Avaliable[0] && Request[num][1] <= Avaliable[1] && Request[num][2] <= Avaliable[2]) {
				for(int i=0;i<3;i++) {
					Avaliable[i] -= Request[num][i];
					Allocation[num][i] += Request[num][i];
					Need[num][i] -= Request[num][i];
				}
			} else {
				System.out.println("当前没有足够资源");
				T = false;
			}
		} else {
			System.out.println("请求超出最大需求量");
			T = false;
		}
		if(T==true) {
			printSystemStatus();
			System.out.println("进入安全检测");
			testSafe();
		}
	}
	
	public void testSafe() {
		boolean[] Finish = {false, false, false};//初始化Finish
        int count = 0;//完成进程数
        int circle=0;//循环圈数
        int[] S = new int[3];//安全序列	
    	Work = Avaliable.clone();
    	boolean flag = true;
    	while(count < 3) {
    		if(flag) {
    			System.out.println("进程  "+"   Work  "+"   Alloction "+"    Need  "+"     Work+Alloction ");
                flag = false;
    		}
    		for(int i=0;i<3;i++) {
    			if (Finish[i]==false&&Need[i][0]<=Work[0]&&Need[i][1]<=Work[1]&&Need[i][2]<=Work[2]) {//判断条件
    				System.out.print("P"+i+"  ");
                    for (int k = 0; k < 3; k++){
                        System.out.print(Work[k]+"  ");
                    }
                    System.out.print("|  ");
                    for (int j = 0; j<3;j++){
                    	Work[j] += Allocation[i][j];	//尝试归还
                    }
                    Finish[i]=true;//当当前进程能满足时
                    S[count]=i;//设置当前序列排号

                    count++;//满足进程数加1
                    for(int j=0;j<3;j++){
                       System.out.print(Allocation[i][j]+"  "); 
                    }
                    System.out.print("|  ");
                    for(int j=0;j<3;j++){
                       System.out.print(Need[i][j]+"  "); 
                    }
                    System.out.print("|  ");
                    for(int j=0;j<3;j++){
                       System.out.print(Work[j]+"  "); 
                    }
                    System.out.println();
    			}    			
    		}
    		circle++;
    		
    		if(count==3) {
    			System.out.println("安全序列存在");
    			for (int i = 0; i<3;i++){//输出安全序列
                    System.out.print("P"+S[i]+" ");
                }
                System.out.println("故当前可分配!");
                break;//跳出循环
    		}
    		if(count<circle){//判断完成进程数是否小于循环圈数
                count=5;
                System.out.println("当前系统处于不安全状态,故不存在安全序列。");
                break;//跳出循环
            }
    	}
	}
	
	public static void main(String[] args) {
        // TODO code application logic here
        boolean Choose = true;
        String C;
        Scanner in = new Scanner(System.in);
        Banker T = new  Banker();
        System.out.println("这是一个三个进程,初始系统可用三类资源为{10,8,7}的银行家算法:");

        T.setSystemVariable();
        while (Choose == true) {
            T.setRequest();
            System.out.println("您是否还要进行请求:y/n?");
            C = in.nextLine();
            if (C.endsWith("n")) {
                Choose = false;
            }
        }
    }
}

测试结果

参考资料

  • 《操作系统》——北大陈向群
  • <a href=https://blog.csdn.net/u014634576/article/details/52600826>银行家算法Java实现</a>