学习记录之进程间死锁

死锁的概念

  • 死锁:由于竞争资源或通信关系,两个或更多进程(线程)在执行过程中出现永远相互等待而引发的事件。死锁对于系统而言是危险的、不安全的,因此在系统的实现时应该考虑避免死锁,或者设计一种可以有效检查死锁并且解决的应急处理方法。

死锁的必要条件

  • 互斥
    任何时候只能由一个进程使用一个资源实例。
  • 持有并等待
    进程保持并占有至少一个资源,并且该进程正在等待一个其他进程正在持有的资源。
  • 非抢占
    资源只能在进程使用后自愿放弃,不存在抢占的情况。
  • 循环等待
    例如:A0占有A1正在等待的资源,而A1又正占有着A0所请求的资源。这是一个循环等待对方释放资源的循环等待。

死锁的处理

  • 死锁预防(Deadlock Prevention)
    通过避免出现死锁的四个必要条件来杜绝死锁的出现。一种武断的处理方式,在不影响实际系统性能时可以使用该方式,但是往往会降低系统的效率,所以该方式要慎用!
  • 死锁避免(Deadlock Avoidance)
    在使用进程前来判断,只允许在不会出现死锁的情况下让进程请求资源。当进程数多时,都进行判断检测是一个耗时耗力的过程,在庞大系统中实行起来困难。
  • 死锁检测&恢复(Deadlock Detection&Recovery)
    在检测到系统进入死锁状态后,进行退回恢复。相较于前两个方式可行性更强,但是需要考虑用什么算法来检测死锁状态,检测的周期是多长,退回恢复操作退回到哪一步等问题。

注意:操作系统对死锁不进行处理,全部交由应用系统来决定。

银行家算法(死锁安全判断)

数据结构
这里先说明一下银行家算法的数据结构,n是系统现在所有的线程数量,m是可被占有的资源类型数量。Max[ i , j ]是线程 i 对资源 j 的需求量,容量为n×m;Available[ i ]表示资源的剩余空闲量;Allocation[ i , j ]表示线程 i 对资源 j 的占有量,总容量为n×m;Need[ i , j ]表示线程 i 对资源 j 的请求量,总容量为n×m。
在明确了以上数据结构后,下面有一个实例,已知Max矩阵为C,Allocation矩阵为A,那么需求矩阵Need为C-A,剩余资源向量Available根据已知资源总量R减去矩阵A每列总和的向量,得到剩余资源向量V。以上就完成了算法的初始化。
初始化状态
接下来进入算法的核心——算法流程。
检测算法
下面是死锁检测算法的Java实现:

public class DeadlockDetection {
	
	public int m = 3;	//m表示可用资源种类
	public int n = 5;	//n表示当前存在进程数
	public int available[] =  new int[m];	//存储每种资源可用数量
	public int allocation[][] = new int[n][m];	//存储各个进程对每种资源的占有量
	public int request[][] = new int[n][m];	//资源请求表
	public boolean finish[] = new boolean[n];	//进程结束表
	private int i;
	
	public DeadlockDetection() {
		//初始表,可由外部进程创建
		available[0] = 0;
		available[1] = 0;
		available[2] = 0;
		allocation[0][0] = 0;
		allocation[0][1] = 1;
		allocation[0][2] = 0;
		allocation[1][0] = 2;
		allocation[1][1] = 0;
		allocation[1][2] = 0;
		allocation[2][0] = 3;
		allocation[2][1] = 0;
		allocation[2][2] = 3;
		allocation[3][0] = 2;
		allocation[3][1] = 1;
		allocation[3][2] = 1;
		allocation[4][0] = 0;
		allocation[4][1] = 0;
		allocation[4][2] = 2;
		request[0][0] = 0;
		request[0][1] = 0;
		request[0][2] = 0;
		request[1][0] = 2;
		request[1][1] = 0;
		request[1][2] = 2;
		request[2][0] = 0;
		request[2][1] = 0;
		request[2][2] = 1;
		request[3][0] = 1;
		request[3][1] = 0;
		request[3][2] = 0;
		request[4][0] = 0;
		request[4][1] = 0;
		request[4][2] = 2;
	}
	
	public void detecte() {
		//初始化剩余资源表work[]
		int work[] = this.available;
		//初始化进程结束表,如果一个进程不占有任何资源,
		//说明该进程不处于死锁的必要条件,该进程被认定为结束。
		for(int i1 = 0; i1<this.n; i1++){
			int x = 0;
			for(int i2 = 0; i2<this.m; i2++){
				x = x+this.allocation[i1][i2];
			}
			if(x == 0){
				this.finish[i1]=true;
			}else {
				this.finish[i1]=false;
			}
		}
		//循环n(进程数)次,刷新进程结束表
		for(int i =0; i<this.n; i++){
			//循环n(进程数)次,遍历各个进程,看剩余资源是否满足某一进程需求
			for(int ii1 =0; ii1<this.n; ii1++){
				if(this.finish[i]){
					work = add(work,this.allocation[i]);
				}else{
					int flag = 0;
					//循环m(资源数)次,遍历该进程的资源需求是否可以被剩余资源满足
					for(int ii2=0; ii2<this.m; ii2++){
						if(this.request[ii1][ii2]<=work[ii2]) {
							flag++;
						}
					}
					if(flag==this.m){	
						work = add(work,this.allocation[i]);
						this.finish[i] = true;
					}
				}
			}
		}
		//以上可以得出算法复杂度=O(n*n*m)
		//循环判定进程结束表,判断是否会产生死锁
		for(i= 0;i<this.n;i++){
			if(!this.finish[i]){
				System.out.println("进程会产生死锁,不安全!!");
				return;
			}
		}
		//通过检测,不会产生死锁
		System.out.println("进程不存在死锁危险~");
	}
	//向量加和运算
	public int[] add(int[] x,int[] y){
		for(int i=0; i<this.m; i++){
			x[i] = x[i]+y[i]; 
		}
		return x;
	}
	
	public static void main(String[] args){
		DeadlockDetection system = new DeadlockDetection();
		system.detecte();
	}
}

以上代码已有充分的备注,这里不再做赘述。

死锁恢复

  1. 结束进程
  • 终止所有死锁进程
  • 一次只终止一个导致死锁的进程直到死锁的消除
  • 终止进程的优先级应有以下顺序
    进程的优先级;
    进程已运行事件以及还需运行事件;
    进程已占有资源;
    进程完成需要的资源;
    终止进程数目
  1. 资源抢占
    前面说到非抢占是死锁的一个必要条件,那么这里产生了死锁的进程可以制定抢占算法来打破这一必要条件,从而解除死锁状态。
  • 选择被抢占进程
    优先选择成本最小的进程。
  • 进程回退
    返回到一些安全状态,重启进程到安全状态。
  • 可能出现饥饿
    同一进程可能一直呗选择被抢占者,那么这样这个低优先级低成本的进程就有可能处于饥饿的状态。

小结

在这里插入图片描述
死锁状态如上图所示,是一种不安全的状态,所以一个良好的软件应该考虑到如何避免死锁的出现,这样才能确保软件一定的安全性。
(本渣处于学习过程中,有理解不对的地方希望大佬指正!!!)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值