1.数据结构
- 可利用的资源向量Available:一个含有m个元素的数组,其中每一个元素代表一类可利拥的资源数目,其初始值是系统中所配置的该类全部可用资源数目,其数值随该类资源的分配改变而改变。如果Available[j]=K,则表示系统中现有Rj类资源K个。
- 最大需求矩阵Max:一个n×m的矩阵,它定义了系统中n个进程中的每一个进程对m类资源的最大需求。如果Max[i,j]=K,则表示进程i需要Rj类资源的最大数目为K。
- 分配矩阵Allocation:一个n×m的矩阵,它定义了系统中每一类资源当前已分配给每一进程的资源数。如果Allocation[i,j]=K,则表示进程i当前已分得Rj类资源的数目为K。
- 需求矩阵Need:一个n×m的矩阵,用以表示每一个进程尚需的各类资源数。如果Need[i,j]=K,则表示进程i还需要Rj类资源K个方能完成其任务。
Need[i,j]=Max[i,j]-Allocation[i,j]
2.银行家算法
在避免死锁的方法中,所施加的限制条件较弱,有可能获得令人满意的系统性能。在该方法中把系统的状态分为安全状态和不安全状态,只要能使系统始终都处于安全状态,便可以避免发生死锁。银行家算法的基本思想是分配资源之前,判断系统是否是安全的;若是,才分配。它是最具有代表性的避免死锁的算法。
设进程cusneed提出请求REQUEST [i],则银行家算法按如下规则进行判断。
(1)如果REQUEST [cusneed] [i]<= NEED[cusneed][i],则转(2);否则,出错。
(2)如果REQUEST [cusneed] [i]<= AVAILABLE[i],则转(3);否则,等待。
(3)系统试探分配资源,修改相关数据:
AVAILABLE[i]-=REQUEST[cusneed][i];
ALLOCATION[cusneed][i]+=REQUEST[cusneed][i];
NEED[cusneed][i]-=REQUEST[cusneed][i];
(4)系统执行安全性检查,如安全,则分配成立;否则试探险性分配作废,系统恢复原状,进程等待。
3.安全性算法
(1)设置两个工作向量Work=AVAILABLE;FINISH
(2)从进程集合中找到一个满足下述条件的进程,
FINISH==false;
NEED<=Work;
如找到,执行(3);否则,执行(4)
(3)设进程获得资源,可顺利执行,直至完成,从而释放资源。
Work=Work+ALLOCATION;
Finish=true;
GOTO 2
(4)如所有的进程Finish= true,则表示安全;否则系统不安全。
主要代码:
安全性检测:
public void allocation(){ flag_i.clear(); for (int i = 0; i < this.processes_Size ; i++) { Finish[i] = false; } for (int i = 0; i < this.Resources_Size ; i++) { Work[0][i] = AvailableTmp[0][i]; } int count = 0; int flag = 0; //flag_i中的个数 while (count < this.processes_Size){ for (int i = 0; i < this.processes_Size ; i++) { if(flag_i.contains(i)){ continue; }else { int k = 0; while (k < this.Resources_Size){ if(NeedTmp[i][k] <= Work[count][k] && (this.Finish[count]==false)){ k++; }else { k = this.Resources_Size+1; } } if(k == this.Resources_Size){ flag_i.add(i); flag++; break; //每次添加一个 } } } // //每走一遍for循环应该找到一个,才能往下执行 if((count+1) == flag){ for (int i = 0; i < this.Resources_Size; i++) { Work_All[count][i] = Work[count][i] + AllocationTmp[(int) flag_i.get(count)][i]; } this.Finish[count] = true; count++; //赋值 for (int i = 0; i < this.Resources_Size; i++) { Work[count][i] = Work_All[count - 1][i]; } } else { count++; System.out.println("第"+count+"次安全性检测失败!"); break; } if(Finish[count-1] == false){ break; } } //跳出循环如果有进程数个值,说明每个进程都能满足,将试分配的值真实分配 if(flag_i.size() == this.processes_Size){ for (int i = 0; i < this.processes_Size; i++) { for (int j = 0; j < this.Resources_Size ; j++) { Allocation[i][j] =AllocationTmp[i][j]; Need[i][j] = NeedTmp[i][j]; } } for (int i = 0; i < this.Resources_Size; i++) { Available[0][i] = AvailableTmp[0][i]; } showResult(); System.out.println("*********************************"); show(); }else { if(flag_i.size() == 0){ System.out.println("不满足任何进程的需求!"); System.out.println("无安全序列!"); System.out.println("******************************"); show(); }else { System.out.println("无安全序列!"); System.out.println("*****************************"); show(); } } }
银行家分配部分:
private void requset() { copy(); System.out.println("请输入要请求资源的进程号:"); String name = scanner.next(); int putInto = -1; //判断输入的是几号进程 for (int i = 0; i < this.processes_Size; i++) { if (name.equals(processes[i])){ putInto = i; } } //如果输入的在进程序列内不存在 if(putInto == -1){ System.out.println("非法输入!"); return; } System.out.println(); System.out.println("请输入再次申请的资源大小:"); int[] num = new int[this.Resources_Size]; //输入的request值 for (int i = 0; i < this.Resources_Size; i++) { num[i] = scanner.nextInt(); } int k = 0; for (int i = 0; i < this.Resources_Size; i++) { if ((num[i] <= Need[putInto][i]) && (num[i] <= Available[0][i])) { k++; } else { if((num[i] > Need[putInto][i])) { System.out.println("申请大于需要的进程!"); System.out.println("***************************"); show(); return; } if(num[i] > Available[0][i]){ System.out.println("资源不足!"); System.out.println("***************************"); show(); return; } } } //跳出说明满足要求尝试分配资源 if(k == this.Resources_Size){ for (int j = 0; j < this.Resources_Size; j++) { NeedTmp[putInto][j] = NeedTmp[putInto][j] - num[j]; AllocationTmp[putInto][j] = AllocationTmp[putInto][j] + num[j]; AvailableTmp[0][j] = AvailableTmp[0][j] - num[j]; } } allocation(); }
但是遇到的问题是,当满足银行家算法但是不满足安全性算法时,怎么将银行家预分配的再次还给初始分配前的值,最终采用临时的副本数组,每次安全性算法都是对副本操作,当满足时,才将原数组改变,然后将其输出,当然还有当一个就是一个进程的所需要的资源已经全部得到,此时应该将其删除序列表,并且将其拿到的资源全部还给系统,以便于其他进程的申请。
删除进程(已经获取到了全部所需要的资源):
private void resReturn(){ int count = 0; int num = 0; while (count < processes_Size) { for (int i = 0; i < this.Resources_Size; i++) { if (Need[count][i] == 0){ num++; } } if(num == Resources_Size){ for (int i = 0; i < this.Resources_Size ; i++) { Available[0][i] = Allocation[count][i]+Available[0][i]; } for (int i = 0; i < this.processes_Size; i++) { for (int j = 0; j < this.Resources_Size; j++) { if(i < count){ Need[i][j] = Need[i][j]; Allocation[i][j] = Allocation[i][j]; processes[i] = processes[i]; }else { Need[i][j] = Need[i+1][j]; Allocation[i][j] = Allocation[i+1][j]; processes[i] = processes[i+1]; } } } processes_Size--; } num = 0; count++; } }
测试用例:
申请资源:
当某个进程所需要的资源全部得到的情况如图: