目录
一、实验目的
1、理解死锁的概念、产生的原因及产生死锁的必要条件;
2、理解解决死锁的常见办法或措施;
3、理解和掌握用银行家算法避免死锁的机制和过程
二、实验内容
1、阐述死锁的概念、产生的原因及产生死锁的必要条件;
2、阐述解决死锁的常见办法或措施;
3、用程序语言表达银行家算法
三、实验原理
1.死锁的概念及原理
多个并发进程因为抢夺临界资源,从而使每个进程都处于等待状态的现象。即一组中的每个进程都在等待仅由本组其它进程才能引起的事件,那么该组进程是死锁的。
2、产生死锁的原因
①竞争不可抢占资源
②竞争可消耗资源
③进程推进顺序不当
3、产生死锁的四个必要条件
①互斥条件:某种资源一次只能被一个进程访问,即某个进程一旦分给某个进程,其它进程只能等该进程访问结束才能够访问。
②不可抢占条件:别的进程已经占有的资源,其它进程不能因为自己的需要去抢占。
③请求和保持条件:一个进程因为没有获取所有的资源而阻塞,对自己已经获得的资源保持不释放。
④循环等待条件:进程队列中的若干进程每一个进程都在等待上一个进程释放所占有的资源,而形成的一种循环等待资源的关系。
满足以上4点必然会出现死锁的现象。
4、解决死锁的常见办法
(1)预防死锁
①破坏互斥条件
简而言之,就是在系统里取消互斥,让一个进程不再独自占有一个资源,这样死锁就不会发生,但是一般互斥条件是不能破坏的,所有解决死锁问题一般不去涉及互斥条件。
②破坏请求和保持条件
两种办法:一是每个进程在运行前必须一次性申请其整个运行过程所需要的全部资源;二是允许一个进程只获取前期运行所需的资源便开始运行,运行过程中逐步释放自己已经使用过的资源并申请新的资源。
优点和缺点:前者实现起来简单,但是资源严重被浪费,易引起“饥饿”现象;后者是对前者的改进,可以降低进程“饥饿”的概率。
③破坏不可抢占条件
规定一个已经保持了某些不可被抢占资源的进程在申请新的资源,提出新的资源而不能得到满足时,必须释放它所保持的所有资源,等待以后需要时申请。
这种方法实现起来比较复杂,而且需要付出很大的代价。
④破坏循环等待条件
对系统所有资源类型进行线性排序,规定每个进程每个进程必须按序号递增的顺序请求资源。一个进程在开始时,可以请求某类资源Ri的单元,以后仅当F(Rj)>F(Ri)时(Rj的序号比Ri的大)时,进程才可以申请Rj的资源。
(2)避免死锁
避免死锁同样是属于实现预防的策略,但并不是实现采取某些限制的措施,而是在资源分配过程中防止系统进入不安全状态,从而避免死锁。一种比较典型的例子就是Dijkstra的银行家算法。
(3)监测死锁
为了能对系统中是否出现了死锁进行监测,在系统中必须:
①保存有关资源的请求和分配信息
②提供一种死锁监测算法。
(4)解除死锁
如果利用死锁监测算法监测出系统中已经发生了死锁,则应该立即采取相应的措施,以解决死锁。常采用的两种解除死锁的方法是:
①抢占资源。从其它进程抢占足够的资源,分配给死锁进程。
②终止或撤销进程。终止系统中的一个或多个死锁进程,从而打破循环环路,破坏死锁。
四、实验思想
1、银行家算法的思想
每一个进程在进入系统时,必须申明运行所需的每种资源的最大数目,其数目不应超过系统所拥有的每种资源总数。当一个进程请求一组资源时,系统必须先确定是否有足够的资源分配给这个进程,若有,则判断把这些资源分配给这个进程胡,是否会使系统处于不安全状态,如果不会才会把资源分配给这个进程,否则让这个进程等待。
2、涉及的一些数据结构
①可利用资源向量Available,记录每一类可用的资源数目。
②最大需求矩阵MAX,记录每一个进程对每种资源的最大需求
③分配矩阵Allocation,记录每类资源已经分配给各个进程的资源数。
④需求矩阵Need,表示每一个进程尚需的各种资源数。
存在的关系:Need[i,j]=Max[i,j]-Allocation[i,j]
i表示进程,j表示资源
3、算法描述
设Requesti是进程Pi的,如果Requesti[j]=K,表示进程Pi需要K个Rj类型的资源。当Pi发出资源请求后,按下列步骤检查:
①若Requesti[j]<=Need[i,j],则转向②;否则认为出错。
②若Requesti[j]<=Available[j],则转向③;否则认为尚无足够的资源。
③系统试着给进程分配资源
Available[j]=Available[j]-Requesti[j];
Allocation[i,j]=Allocation[i,j]+Requesti[j];
Need[i,j]=Need[i,j]-Requesti[j];
④执行安全性算法,检查分配后系统处于安全状态。若安全,正式分配;若不安全,本次分配作废,回复原来的资源分配状态。
算法图解
五、实验程序
演示实例
进程\资源情况 | Max | Allocation | Need | Available |
A B C | A B C | A B C | A B C | |
P0 | 7 5 3 | 0 1 0 | 7 4 3 | 3 3 2 |
P1 | 3 2 2 | 2 0 0 | 1 2 2 | |
P2 | 9 0 2 | 3 0 2 | 6 0 0 | |
P3 | 2 2 2 | 2 1 1 | 0 1 1 | |
P4 | 4 3 3 | 0 0 2 | 4 3 1 |
程序展示:
import java.util.Scanner;
public class BankerTest {
int[][] Max = new int[][]{{7,5,3},{3,2,2},{9,0,2},{2,2,2},{4,3,3,}};//每个进程最多需要的各个资源数
int[][] Allocation = new int[][]{{0,1,0},{2,0,0},{3,0,2},{2,1,1},{0,0,2}};//每个进程目前拥有的资源数
int[][] Need = new int[][]{{7,4,3},{1,2,2},{6,0,0},{0,1,1},{4,3,1}};//每个进程需要的资源数
int[] Available = new int[]{3,3,2};//可利用的资源
boolean[] finish = new boolean[]{false,false,false,false,false};
int[] safe = new int[5];//用于在安全算法中保存安全序列
void showData() {
//展示数据输出每个进程的相关数
System.out.println("进程号 Max Allocation Need ");
System.out.println(" A B C A B C A B C");
for(int i = 0;i<5;i++){
System.out.print(i+" ");
for(int m = 0;m<3;m++) System.out.print(Max[i][m]+" ");
System.out.print(" ");
for(int m = 0;m<3;m++) System.out.print(Allocation[i][m]+" ");
System.out.print(" ");
for(int m = 0;m<3;m++) System.out.print(Need[i][m]+" ");
System.out.println();
}
}
void showAvailable(){
System.out.println("当前可分配的各类资源数目为:A B C");
System.out.println(" "+Available[0]+" "+Available[1]+" "+Available[2]);
}
void banker(int processNum,int[] request){//进程号,对各类资源的需求数组
//判断是否满足分配的条件
if(request[0]<=Need[processNum][0] && request[1]<=Need[processNum][1] && request[2]<=Need[processNum][2]){
if(request[0]<=Available[0] && request[1]<=Available[1] && request[2]<=Available[2]){
System.out.println("满足条件,开始试分配");
// finish[processNum] = true;//设置为true,表示有足够的资源分配给该进程
for (int i = 0; i < 3; i++) {
Available[i] -= request[i];
Allocation[processNum][i] += request[i];
Need[processNum][i] -= request[i];
}
//判断是否满足释放条件
//执行安全性算法,确认是否可以分配
System.out.println("试分配结束,进行安全性测试。。。。。");
if (isSafe(processNum, Available)) {
System.out.println("满足安全性算法");
System.out.print("安全序列为:");
for (int i = 0; i < 5; i++) {
System.out.print(safe[i] + " ");
}
} else {
System.out.println("不满足安全性算法,不予分配,恢复数据");
for (int i = 0; i < 3; i++) {
Available[i] += request[i];
Allocation[processNum][i] -= request[i];
Need[processNum][i] += request[i];
}
}
}else{
System.out.println("尚无足够资源!");
}
}else {
System.out.println("请求的资源数目大于需求的资源数目,出现错误!");
}
}
boolean isSafe(int processNum,int[] available){
int[] work = new int[3];//为了与类中的available区分开
for (int i = 0; i < 3; i++) {
work[i] = available[i];
}
int k = 0,j = 0;
while(k < 5){//判断是否还能找到需求资源小于可分配资源的进程
if(!finish[k] && Need[k][0] <= work[0] && Need[k][1] <= work[1] && Need[k][2] <= work[2]){
work[0] += Allocation[k][0];
work[1] += Allocation[k][1];
work[2] += Allocation[k][2];
finish[k]=true;
safe[j++] = k;
k = 0;//如果找到的话,重新开始遍历(为了避免一个进程不满足条件,
// 但是下一个进程满足条件且释放后资源后,这个进程有满足条件,却被误认为不能执行的情况)
}else{
k++;//找不到则找下一个
}
}
for(int i=0;i < 5;i++){
if(!finish[i]){//如果有finish[i]==false的情况就return false
return false;
}
}
//如果以上条件都能满足,则证明满足安全性算法
return true;
}
boolean isExit(int num){//是否结束
if(num==-1){
return true;
}else{
return false;
}
}
void demo(){
Scanner scan = new Scanner(System.in);
while(true){
System.out.println("银行家算法模拟开始:..............");
System.out.print("输入请求资源的进程号:");
int processNum = scan.nextInt();
showAvailable();//展示当前可分配资源
System.out.print("输入请求的各个资源数目(A B C):");
int a = scan.nextInt();
int b = scan.nextInt();
int c = scan.nextInt();
int[] request = new int[]{a,b,c};
banker(processNum,request);
System.out.println("\n");
showAvailable();
//判断是否满足资源释放条件,满足则释放资源
if(isRelease(processNum)){
System.out.println("进程号为" + processNum + "的进程满足资源释放的条件,释放资源");
Available[0] += Allocation[processNum][0];
Available[1] += Allocation[processNum][1];
Available[2] += Allocation[processNum][2];
}else{
System.out.println("不满足释放资源的条件,请继续请求资源");
}
System.out.println("当前数据:");
showData();
showAvailable();
System.out.println("结束吗(确定结束输入-1)");
int num = scan.nextInt();
if(isExit(num))break;
}
}
boolean isRelease(int processNum){//判断一个进程是否满足资源释放的条件
if(Allocation[processNum][0] == Max[processNum][0] &&
Allocation[processNum][1] == Max[processNum][1] &&
Allocation[processNum][2] == Max[processNum][2]){
return true;
}
return false;
}
public static void main(String[] args) {
BankerTest b = new BankerTest();
b.showData();
b.demo();
}
}
结果展示: