操作系统 实验二 银行家算法(java)

操作系统实验 银行家算法 (java)

1.实验目的

加深学生对银行家算法的理解,进一步深入理解死锁、产生死锁的必要条件、安全状态等重要概念,并掌握避免死锁的具体实施方法。

2.实验内容

假定系统中有五个进程{P0, P1, P2, P3, P4}和三类资源{A, B, C},各种资源的数量分别为10、5、7,在T0时刻的资源分配情况如图所示。

java 银行家算法可以避免死锁吗 银行家算法实验报告java_java


用程序模拟实现:

(1) T0时刻的安全性;

(2) P1请求资源:P1发出请求向量Request1(1,0,2),系统按银行家算法进行检查;

(3) P4请求资源:P4发出请求向量Request4(3,3,0),系统按银行家算法进行检查;

(4) P0请求资源:P0发出请求向量Requst0(0,2,0),系统按银行家算法进行检查;

(5) P0请求资源:若P0发出请求向量Requst0(0,1,0),系统按银行家算法进行检查:

3.运用知识

银行家算法
数据结构:

长度为m的一维数组 Available表示还有多少可用资源

nm矩阵Max表示各进程对资源的最大需求数

nm矩阵Allocation表示已经给各进程分配了多少资源

Max - Allocation = Need矩阵表示各进程最多还需要多少资源

用长度为m的一位数组Request表示进程此次申请的各种资源数

银行家算法步骤:

①检查此次申请是否超过了之前声明的最大需求数

②检查此时系统剩余的可用资源是否还能满足这次请求

③试探着分配,更改各数据结构

④用安全性算法检查此次分配是否会导致系统进入不安全状态

安全性算法步骤:

检查当前的剩余可用资源是否能满足某个进程的最大需求,如果可以,就把该进程加入安全序列,并把该进程持有的资源全部回收。 不断重复上述过程,看最终是否能让所有进程都加入安全序列 ———————————————— 以上内容采自作者:「一只不吃老鼠的猫」以获取作者同意)

以下的代码设计中也采用了该作者的部分思想和设计理念,并在原来的基础上做了本次实验需要的更改和添加一些本次实验需要的内容。

4.代码设计

本文代码由于实验关系考虑内容较多,也可能增加部分不重要的内容,如果觉得难以理解可以先看看上述作者的文章。

以下代码中标注为“ //实验过程需要输出 ” 是实验要求输出表格用的,与算法无关

package com.atM.taskSystemTest.task2;

/**
 * @author M.博
 * @version 1.0.0
 * @ClassName BankerAlgorithm.java
 * @Description 操作系统实验二 银行家算法
 */

import java.util.Scanner;

public class BankerAlgorithm {
    static int pro_nums;  // 进程数量
    static int resType_nums;  // 资源种类数量
    static int[][] maxNeed;     // 最大需求矩阵
    static int[] maxInt;     // 初始态各种资源数量矩阵(本次实验中分别是10 5 7)
    static int[][] allocation;   // 分配矩阵
    static int[][] need;    // 需求矩阵
    static int[] ava;     // 可用资源数向量
    static int[] request;  //某进程的请求向量(本次申请的资源量)
    static int[] safe_seq; //安全序列数组
    static int[] work; //表示系统可提供给进程继续运行所需的各类资源数目
    static int[][] workAddAlloc;
    static int[][] works; //表示系统可提供给每个进程继续运行所需的各类资源数目

    /**
     * @description: 对变量进行初始化
     * @return: void
     * @author M.博
     */
    static void pro_init() {
        Scanner in = new Scanner(System.in);
        System.out.println("请输入进程数量:");
        pro_nums = in.nextInt();
      //  pro_nums = 5;  //实验测试过程写死
        System.out.println("请输入资源种类数量");
        resType_nums = in.nextInt();
      //  resType_nums = 3;  //实验测试过程写死
        safe_seq = new int[pro_nums + 1];
        maxNeed = new int[pro_nums][resType_nums];
        maxInt = new int[resType_nums];
        allocation = new int[pro_nums][resType_nums];
        need = new int[pro_nums][resType_nums];
        ava = new int[resType_nums];
        workAddAlloc = new int[pro_nums][resType_nums];

        System.out.println("请输入各种资源总数量:");
        for (int i = 0; i < resType_nums; i++) {
            maxInt[i] = in.nextInt();
        }
      //  maxInt = new int[]{10, 5, 7};   //实验测试过程写死
        System.out.println("请输入每个进程分别对应的最大资源数:");
        for (int i = 0; i < pro_nums; i++) {
            for (int j = 0; j < resType_nums; j++) {
                maxNeed[i][j] = in.nextInt();
            }
        }
      //  maxNeed = new int[][]{{7, 5, 3}, {3, 2, 2}, {9, 0, 2}, {2, 2, 2}, {4, 3, 3}};  //实验测试过程写死
        System.out.println("请输入每个进程分别对应的分配资源数:");
        for (int i = 0; i < pro_nums; i++) {
            for (int j = 0; j < resType_nums; j++) {
                allocation[i][j] = in.nextInt();
            }
        }
       // allocation = new int[][]{{0, 1, 0}, {2, 0, 0}, {3, 0, 2}, {2, 1, 1}, {0, 0, 2}};  //实验测试过程写死

        //计算需求矩阵
        for (int i = 0; i < pro_nums; i++) {
            for (int j = 0; j < resType_nums; j++) {
                need[i][j] = maxNeed[i][j] - allocation[i][j];
            }
        }
        //计算可用资源向量
        for (int j = 0, i = 0; j < resType_nums; j++) {
            for (i = 0; i < pro_nums; i++) {
                maxInt[j] -= allocation[i][j];
            }
            ava[j] = maxInt[j];
        }
    }

    /**
    * @description: 比较 :进程为work中的元素需要全大于need中的元素
     *                转义为 :如果有一对need中的元素大于work中的元素即返回false
    * @param: work need
    * @return: boolean
    * @author M.博
    */
    static boolean compare(int[] work, int[] need) {
        for (int i = 0; i < resType_nums; i++) {
            if (need[i] > work[i])
                return false;
        }
        return true;
    }
    /**
    * @description: 获取最大可出现比较不合格的次数且finish没有全部为flash
     *              本文会简单给出解释
    * @param: num  这里为进程数
    * @return: int
    * @author M.博
    */
    static int getQualifiedMax(int num){
        int sum=1;
        if(num<0) {
            throw new IllegalArgumentException("需要参数为正数!");
        }
        for(int i=1;i<=num;i++) {
            sum+=i;
        }
        return sum;
    }

    /**
    * @description: 安全性检验函数,检测是否存在安全序列
    * @return: boolean
    * @author M.博
    */
    static boolean safe() {
        boolean[] finish = new boolean[pro_nums];
        work = new int[resType_nums];
        works = new int[pro_nums][resType_nums];
        //这里注意不能用=赋值,不理解的话,下面会给出简单解释
        System.arraycopy(ava, 0, work, 0, resType_nums);
        int safe_i = 0;//安全序列当前指针位置
        int qualified_num = 0;//用来判断巡查过程中,如果连续比较都不合格且超过qualifiedMax次时退出循环,避免死循环
        int qualifiedMax = getQualifiedMax(pro_nums-1);//获取qualified_num能达到的最大限度, 明显最坏情况序列为43210
        //巡查
        while (safe_i < pro_nums && qualified_num < qualifiedMax) {
            for (int i = 0; i < pro_nums; i++) {
                if (!finish[i]) {
                    if (compare(work, need[i])) {
                        qualified_num--; //如果进入到这一步说明比较过程符合要求,记得将控制型变量减一
                        finish[i] = true;
                        safe_seq[safe_i++] = i;
                        if (safe_i == 1) {
                            System.arraycopy(ava, 0, works[i], 0, resType_nums);
                        } else {
                            System.arraycopy(work, 0, works[i], 0, resType_nums);
                        }
                        //释放进程资源,更新work
                        for (int j = 0; j < resType_nums; j++) {
                            work[j] = work[j] + allocation[i][j];
                        }
                        System.arraycopy(work, 0, workAddAlloc[i], 0, resType_nums);
                    } else qualified_num++;
                }
            }
        }
        for (int i = 0; i < pro_nums; i++) {
            if (!finish[i])
                return false;
        }
        return true;
    }


    /**
    * @description:  申请进程后的安全性检验函数
    * @param: n 代表进程号
    * @author M.博
    */
    static void reSafe(int n) {
        //available>=request 并且 need >=request
        if (compare(ava, request) && compare(need[n], request)) {
            for (int i = 0; i < resType_nums; i++) {
                allocation[n][i] = allocation[n][i] + request[i];
                need[n][i] = need[n][i] - request[i];
                ava[i] = ava[i] - request[i];
            }
            if (safe()) {
                System.out.println("允许进程" + n + "申请资源");
                System.out.println("安全序列分配成功");
                printSafetySequenceTable();  //实验过程需要输出
                printStateTable();  //实验过程需要输出
            } else {
                System.out.println("不允许进程" + n + "申请资源");
                System.out.println("不存在安全序列,不是安全状态");
                for (int i = 0; i < resType_nums; i++) {
                    allocation[n][i] = allocation[n][i] - request[i];
                    need[n][i] = need[n][i] + request[i];
                    ava[i] = ava[i] + request[i];
                }
            }
        } else
            System.out.println("可用资源已经不满足如何进程的需要,申请资源量越界");
    }
    //实验过程需要输出
    static void printStateTable() {
        System.out.println("状态表如下:");
        System.out.println("|Process     |Max         |Allocation  |Need        |Available");
        for (int i = 0; i < pro_nums; i++) {
            System.out.print("|P" + i + "          ");
            state_toPrint(maxNeed, i);
            state_toPrint(allocation, i);
            state_toPrint(need, i);
            if (i == 0) {
                state_toPrint(ava);
            }
            System.out.println();
        }
    }
    //实验过程需要输出
    static void printSafetySequenceTable() {
        System.out.println("安全序列表如下:");
        System.out.println("|Process     |Work        |Need        |Allocation  |Work+Allocation |Finish");
        for (int i = 0; i < pro_nums; i++) {
            System.out.print("|P" + i + "          ");
            state_toPrint(works, i);
            state_toPrint(need, i);
            state_toPrint(allocation, i);
            state_toPrint(workAddAlloc, i);
            System.out.print("    |True");
            System.out.println();
        }
    }
    //实验过程需要输出
    static void printSafetySequenceTableOfInt() {
        System.out.print("安全序列为: ");
        for (int i = 0; i < pro_nums; i++) {
            System.out.print(safe_seq[i] + " ");
        }
        System.out.println();
        System.out.println("安全序列表如下:");
        System.out.println("|Process     |Work        |Need        |Allocation  |Work+Allocation |Finish");
        for (int i = 0; i < pro_nums; i++) {
            System.out.print("|P" + safe_seq[i] + "          ");
            state_toPrint(works, safe_seq[i]);
            state_toPrint(need, safe_seq[i]);
            state_toPrint(allocation, safe_seq[i]);
            state_toPrint(workAddAlloc, safe_seq[i]);
            System.out.print("    |True");
            System.out.println();
        }
    }
    //实验过程需要输出
    static void state_toPrint(int[] arrays) {
        System.out.print("|");
        for (int a : arrays) {
            System.out.print("   " + a);
        }
    }
    //实验过程需要输出
    static void state_toPrint(int[][] arrays, int i) {
        System.out.print("|");
        for (int j = 0; j < arrays[i].length; j++) {
            System.out.print("   " + arrays[i][j]);

        }
    }

    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        //进程编号
        int n;
        pro_init();
        //实验过程需要输出
        printStateTable();
        if (safe()) {
            System.out.println("  存在安全序列,初始状态安全。");
            //实验过程需要输出
            printSafetySequenceTableOfInt();
        } else
            System.out.println("不存在安全序列,初始状态不安全。");
        //这里一直进行循环使用,如果是单次运用可以去除while循环,也可以增加退出循环方式,本文不做添加
        while (true) {
            System.out.println("请输入发出请求向量request的进程编号:");
            n = in.nextInt();
            request = new int[resType_nums];
            System.out.println("请输入请求向量request:");
            for (int i = 0; i < resType_nums; i++) {
                request[i] = in.nextInt();
            }
            reSafe(n);
        }

    }
}

5.运行结果演示

java 银行家算法可以避免死锁吗 银行家算法实验报告java_System_02

java 银行家算法可以避免死锁吗 银行家算法实验报告java_java 银行家算法可以避免死锁吗_03

java 银行家算法可以避免死锁吗 银行家算法实验报告java_System_04

java 银行家算法可以避免死锁吗 银行家算法实验报告java_开发语言_05

java 银行家算法可以避免死锁吗 银行家算法实验报告java_java_06

java 银行家算法可以避免死锁吗 银行家算法实验报告java_System_07


java 银行家算法可以避免死锁吗 银行家算法实验报告java_java 银行家算法可以避免死锁吗_08

6.实验中可能出现的问题及部分解释

问题及解释
问题一 变量

一定要确保变量是不是全局变量,本次实验过程是重复利用上次实验结果的数据,需要用的全局变量,而部分变量如finish布尔组不是全局变量,每次都要重新初始化,原因是每次实验,finish保存的是本次实验的结果,如果是全局变量会影响下一次实验,造成下一次实验可能不能进入比较环节.

问题二 safe函数
int qualified_num = 0;//用来判断巡查过程中,如果连续比较都不合格且超过qualifiedMax次时退出循环,避免死循环
int qualifiedMax = getQualifiedMax(pro_nums-1);//获取qualified_num能达到的最大限度, 明显最坏情况序列为43210

如果没有这两个变量去限制while循环,并且每次过来的数据在比较过程中都不符合要求,会导致循环一直进行,造成死循环,不理解的朋友可以去掉这两个变量debug试试,很好理解。

一个要注意如果比较过程中达到要求,因为需要多次需要知道找到合适的安全序列,所以需要将该qualified_num变量减一。

qualifiedMax的求法其实很简单,最坏的情况应该是每次循环都是从最后一个进程中选择,本次实验就是4 3 2 1 0. 那么的qualified_num值就是(4-1) +(3-1)+(2-1)+(1-1)。

问题三 数组不能用=赋值

简单解释: =赋值 是地址上的改变,如果其中一个数组内容改变,另一个数组内容也会改变
所以这里我们用copy的方法,也可以使用Arrays工具里的copy

ps:如果有哪里写的不对,还请赐教