死锁是指两个(多个)线程相互等待对方数据的过程,死锁的产生会导致程序卡死,不解锁程序将永远无法进行下去。
1、死锁产生原因
举个例子:两个线程A和B,两个数据1和2。线程A在执行过程中,首先对资源1加锁,然后再去给资源2 加锁,但是由于线程的切换,导致线程A没能给资源2加锁。线程切换到B后,线程B先对资源2加锁,然 后再去给资源1加锁,由于资源1已经被线程A加锁,因此线程B无法加锁成功,当线程切换为A时,A也 无法成功对资源2加锁,由此就造成了线程AB双方相互对一个已加锁资源的等待,死锁产生。
理论上认为死锁产生有以下四个必要条件,缺一不可:
1. 互斥条件:进程对所需求的资源具有排他性,若有其他进程请求该资源,请求进程只能等待。
2. 不剥夺条件:进程在所获得的资源未释放前,不能被其他进程强行夺走,只能自己释放。
3. 请求和保持条件:进程当前所拥有的资源在进程请求其他新资源时,由该进程继续占有。
4. 循环等待条件:存在一种进程资源循环等待链,链中每个进程已获得的资源同时被链中下一个进程所请求。
3、死锁的解决方案:
保证上锁的顺序一致。
5、处理方法
鸵鸟策略:
把头埋在沙子里,假装根本没发生问题。 因为解决死锁问题的代价很高,因此鸵鸟策略这种不采取任务措施的方案会获得更高的性能。 当发生死锁时不会对用户造成多大影响,或发生死锁的概率很低,可以采用鸵鸟策略。 大多数操作系统,包括 Unix,Linux 和 Windows,处理死锁问题的办法仅仅是忽略它。
死锁检测与死锁恢复
1.不试图阻止死锁,而是当检测到死锁发生时,采取措施进行恢复。
2.利用抢占恢复、利用回滚恢复、通过杀死进程恢复
死锁预防
在程序运行之前预防发生死锁。
1. 破坏互斥条件
例如假脱机打印机技术允许若干个进程同时输出,唯一真正请求物理打印机的进程是打印机守护进 程。
2. 破坏请求和保持条件
一种实现方式是规定所有进程在开始执行前请求所需要的全部资源。
3. 破坏不剥夺条件
允许抢占资源
4. 破坏循环请求等待
给资源统一编号,进程只能按编号顺序来请求资源。
死锁避免
在程序运行时避免发生死锁。
1. 安全状态
定义:如果没有死锁发生,并且即使所有进程突然请求对资源的最大需求,也仍然存在某种调度次序能 够使得每一个进程运行完毕,则称该状态是安全的。
安全状态的检测与死锁的检测类似,因为安全状态必须要求不能发生死锁。下面的银行家算法与死锁检 测算法非常类似,可以结合着做参考对比。
2. 单个资源的银行家算法
一个小城镇的银行家,他向一群客户分别承诺了一定的贷款额度,算法要做的是判断对请求的满足是否 会进入不安全状态,如果是,就拒绝请求;否则予以分配。
上图 c 为不安全状态,因此算法会拒绝之前的请求,从而避免进入图 c 中的状态。
3. 多个资源的银行家算法
上图中有五个进程,四个资源。左边的图表示已经分配的资源,右边的图表示还需要分配的资源。最右 边的 E、P 以及 A 分别表示:总资源、已分配资源以及可用资源,注意这三个为向量,而不是具体数 值,例如 A=(1020),表示 4 个资源分别还剩下 1/0/2/0。
4、检查一个状态是否安全的算法如下:
查找右边的矩阵是否存在一行小于等于向量 A。如果不存在这样的行,那么系统将会发生死锁,状态 是不安全的。
假若找到这样一行,将该进程标记为终止,并将其已分配资源加到 A 中。
重复以上两步,直到所有进程都标记为终止,则状态时安全的。
如果一个状态不是安全的,需要拒绝进入这个状态。