在银行家算法中,发现这样一个问题:在网上的大多数代码资料中,进程的已分配资源是手动输入的,其目的是保证系统可用资源能使至少一个进程执行,但在实际操作中,对系统而言,在用户的操作下,进程的资源需求可以看作是随机的。若是系统的资源无法满足任意一个进程执行,那么将产生死锁,这样的情况应该是少见的。针对这样一个问题,在此算法基础之上,做出假设。当系统的资源无法满足任意一个进程执行时。根据对银行家算法的理解,银行家算法前提是以一个进程的资源释放为基础,采用释放掉某个进程已拥有资源的策略。不难想象,在当系统发现一个进程都无法执行时,可以释放一个进程或多个进程已拥有的资源,可以看作是系统剥夺进程的资源,可以再进行银行家算法,实现安全状态
在操作系统中还有一种鸵鸟算法,就是忽视问题。鸵鸟算法可以看作解决该问题的解决方式的一个极限。这种解决问题的方式可以看作实在逃避问题(逃避虽可耻但有用),逃避的目的积累能量,在找到突破口后,利用银行家算法滚雪球的优势解决问题(集中力量办大事,面对困难奥利给)。
程序(JAVA)实现上,当系统的资源无法满足任意一个进程执行时,采用随机的释放掉一个进程的方式,直到可以执行一个程序为止。可以说这是一种简单的策略,当然还可以考虑更多的条件,比如该释放哪一个进程(按优先级或是按进程已占资源的多少),释放进程的哪一类资源(内存、显存…)。我采用的是随机选择的方式。这种的方式实现简单,而且此时的系统资源本来就很紧张了。在解决这种少见问题的方式上,可以类比于用户打开windows操作系统上的任务管理器结束进程,当然更极端的方式是长按电源键,实现重启,也算是鸵鸟式操作。代码如下
进程对象:
import java.util.Random; /* * author@ 蒋龙荣 2020-03-19 * * Proceeding 类 将进程看作对象 * 属性: * 进程所需最大 A B C 资源 , @A_MaxRequire,@B_MaxRequire,@C_MaxRequire * 已分配资源 @A_AlreadyGet,@B_AlreadyGet,@C_AlreadyGet * 进程还需要的资源 @A_Need,@B_Need,@C_Need * 进程状态 @Status * 进程ID @ProcessingID */ public class Process { // 进程需要的A、B、C类最大资源 int A_MaxRequire; int B_MaxRequire; int C_MaxRequire; // 进程已经分配到的A、B、C类资源 int A_AlreadyGet; int B_AlreadyGet; int C_AlreadyGet; // 进程还需要的A、B、C类资源 private int A_Need; private int B_Need; private int C_Need; // 进程的状态 Wating(等待),Keilled(结束) String Status = "Waiting"; //进程本身的ID public int ProcessID ; Random random = new Random(); public Process(int a_maxRequire, int b_maxRequire, int c_maxRequire, int a_alreadyGet, int b_alreadyGet,int c_alreadyGet, int proceedingID) { this.A_MaxRequire = a_maxRequire; this.B_MaxRequire = b_maxRequire; this.C_MaxRequire = c_maxRequire; this.A_AlreadyGet = a_alreadyGet; this.B_AlreadyGet = b_alreadyGet; this.C_AlreadyGet = c_alreadyGet; this.ProcessID = proceedingID; this.ProcessNeed(); this.JudgeStatus(); this.toString(); } public Process() { } // 随机生成进程所需的最大资源 public void GenerateMaxRequire() { A_MaxRequire = random.nextInt(14); // waiting for change B_MaxRequire = random.nextInt(8); C_MaxRequire = random.nextInt(7); } // 在不超过当前资源最大值情况下随机生成已获得的资源 public void GenerateAlreadyGet(Process lastProcess) { Source.A_Source = Source.A_Source - lastProcess.A_AlreadyGet; A_AlreadyGet = random.nextInt(Source.A_Source); Source.B_Source = Source.B_Source - lastProcess.B_AlreadyGet; B_AlreadyGet = random.nextInt(Source.B_Source); Source.C_Source = Source.C_Source - lastProcess.C_AlreadyGet; C_AlreadyGet = random.nextInt(Source.C_Source); } // 计算需要的资源 public void ProcessNeed() { A_Need = A_MaxRequire - A_AlreadyGet; // waiting for change B_Need = B_MaxRequire - B_AlreadyGet; C_Need = C_MaxRequire - C_AlreadyGet; } // 判断进程状态 waiting 或 killed public void JudgeStatus() { if (A_MaxRequire > A_AlreadyGet || B_MaxRequire > B_AlreadyGet || C_MaxRequire > C_AlreadyGet) Status = "Waiting"; else Status = "Killed"; } // 释放该进程的资源(在未找到安全的序列时) public void ReleaseSource() { Source.A_Source = Source.A_Source + this.A_AlreadyGet; Source.B_Source = Source.B_Source + this.B_AlreadyGet; Source.C_Source = Source.C_Source + this.C_AlreadyGet; this.A_AlreadyGet = 0; this.B_AlreadyGet = 0; this.C_AlreadyGet = 0; } @Override public String toString() { return "\nA_MaxRequire=" + A_MaxRequire + ", B_MaxRequire=" + B_MaxRequire + ", C_MaxRequire=" + C_MaxRequire + ", \nA_AlreadyGet=" + A_AlreadyGet + ", B_AlreadyGet=" + B_AlreadyGet + ", C_AlreadyGet=" + C_AlreadyGet + ", \nA_Need=" + A_Need + ", \tB_Need=" + B_Need + ", \tC_Need=" + C_Need + ", \nStatus=" + Status +"\t"+"ProcessID: "+ProcessID+ "\n\n"; }
资源对象:
public class Source { //各种资源的情况 public static int A_Source = 15; public static int B_Source = 12; public static int C_Source = 9; public static String ToString() { return "Source [A_Source=" + A_Source + ", B_Source=" + B_Source + ", C_Source=" + C_Source + "]\n"; } }
算法部分:
/* * author @ 蒋龙荣 170404121 2020-03-20 * 软件技术基础作业 * 进程组@test.Process * 待排序的进程组容器@CompareSequence,用于等待排好序的进程 * 已排好序的进程组的容器@ProcessSequence,用于容纳已经排好序的进程 */ import java.util.Objects; import java.util.Random; public class test { // 假设有 5 个进程 static Process[] Process = new Process[5]; // 已排好序的进程组的容器 static Process[] ProcessSequence = new Process[5]; // 待排序的进程组容器 static Process[] CompareSequence = new Process[5]; //资源对象 static Source source = new Source(); public static void Initialize() { //初始化 进程组@test.Process,待排序的进程组容器@CompareSequence,已排好序的进程组的容器@ProcessSequence ,一共 5 个进程 test.Process[0] = new Process(5, 6, 3, 1, 2, 1, 0);//初始化第 0 个 CompareSequence[0] = new Process(0, 0, 0, 0, 0, 0, -1); ProcessSequence[0] = new Process(0, 0, 0, 0, 0, 0, -2); System.out.print("Proceeding_0" + test.Process[0].toString()); //从 第 1 个开始初始化 for (int i = 1; i < 5; i++) { // Took me long time find the nullpointer bug // Initialize the objects first!!!!!!! test.Process[i] = new Process(); // 生成进程 ID test.Process[i].ProcessID = i; // 生成所需进程最大的资源需求 test.Process[i].GenerateMaxRequire(); // 生成进程已经得到的资源 test.Process[i].GenerateAlreadyGet(test.Process[i - 1]); // 根据上一个进程随机分配资源 // 计算进程所需的资源 MaxRequire - AlreadyGet test.Process[i].ProcessNeed(); // 判断进程的状态 test.Process[i].JudgeStatus(); System.out.print("Process_" + i + test.Process[i].toString()); CompareSequence[i] = new Process(0, 0, 0, 0, 0, 0, -1); ProcessSequence[i] = new Process(0, 0, 0, 0, 0, 0, -2); } //计算最后剩下的资源 Source.A_Source = Source.A_Source - test.Process[4].A_AlreadyGet; Source.B_Source = Source.B_Source - test.Process[4].B_AlreadyGet; Source.C_Source = Source.C_Source - test.Process[4].C_AlreadyGet; System.out.print("After ini tializing,the left Source: "+Source.ToString()); } public static void main(String[] args) { Random ran = new Random(); // 待排序的进程组容器的序号 int j = 0; // 已排好序进程组容器的序号 int k = 0; //初始化 test.Initialize(); // 第一次排序,用于检查一开始可以执行的进程 for (int i = 0; i < 5; i++) { //判断进程预分配的资源是否满足运行要求 if (Objects.equals("Killed", Process[i].Status)) { // 预分配的资源满足运行要求,释放该进程资源 Process[i].ReleaseSource(); // 装入已排好序进程组容器 ProcessSequence[k] = Process[i]; //序号加 1 k++; } else // 将进程转入待进程组容器,等待分配资源 { CompareSequence[j] = Process[i]; //序号加一 j++; } } // 有 j 次循环, j 表示待排序的进程数 again: for (int i = 0; i < j; i++) { // 在初始分配时就满足所有进程所需资源 if (j == 0) // 跳出循环 break; // 尝试分配资源给进程 else if (((CompareSequence[i].A_AlreadyGet + Source.A_Source) >= CompareSequence[i].A_MaxRequire) && ((CompareSequence[i].B_AlreadyGet + Source.B_Source) >= CompareSequence[i].B_MaxRequire) && ((CompareSequence[i].C_AlreadyGet + Source.C_Source) >= CompareSequence[i].C_MaxRequire)) { // 释放内存 CompareSequence[i].ReleaseSource(); // 将进程装入执行进程组 ProcessSequence[k] = CompareSequence[i]; // 执行进程组的个数加 1 k++; // 待比较的进程组个数减 1 j--; // 将待比较的进程序列从 i 处开始,向前移一位 for (int m = i; m < 4; m++) CompareSequence[m] = CompareSequence[m + 1]; i = -1; continue again; //无法找到一个可以进行的进程 } else if (i == j - 1) { //产生随机数,随机指定待排序的进程组中的一个进程释放资源 int num = ran.nextInt(5); //释放资源 CompareSequence[num].ReleaseSource(); System.out.print( "Have relased the process,the process ID is " + CompareSequence[num].ProcessID + "\n"); //初始化循环 i = -1; //跳至循环开头,从新开始循环,从待排序的 continue again; } //找到一个可以进行的进程或是未完判断此次待排序的进程组,继续循环 continue; } // 输出排序好后的进程 ID System.out.print("The execution sequence of the process ID:\n "); for (int i = 0; i < 5; i++) { System.out.print(ProcessSequence[i].ProcessID + "\t"); } } }
运行结果:
在此次运行的过程中,出现了在不释放进程已获资源的情况下,无法执行进程的情况,同时在随机释放进程已获资源的情况的策略中,出现多次释放同一进程的情况,导致释放资源无效,进而再次随机释放进程资源,出现无效释放的情况,这种情况也许比较少见,也是设计的一个缺陷。
原文:https://www.cnblogs.com/jianglongrong/p/12540618.html