死锁的概念
多个进程都被阻塞,并一直处于这样的状态,这种状态称为死锁。
死锁的分类
死锁分为两类:资源死锁和通信死锁。
资源死锁是由于多个进程或线程同时获取多个资源时发生。下面这段代码就可能发生死锁。
semaphore resource1;
semaphore resource2;
void process_A(void){
down(resource1);
down(resource2);
use_resource();
up(resource1);
up(resource2);
}
void process_B(void){
down(resource2);
down(resource1);
use_resource();
up(resource1);
up(resource2);
}
通信死锁是由于网络延时或丢包,导致两个进程都在等待对方的数据。可以通过超时重发机制解决。
死锁四个条件
- 互斥条件。一个资源不能同时被多个进程访问
- 占有和等待条件。一个资源已经被另一个进程占用,那么该进程只能等待。
- 不可抢占。已经分配给某个进程的资源,不能通过调度的方式抢占该资源。
- 环路等待条件。多个进程和资源组成环路。
t例如上图中,p1和p2表示两个进程,s1和s2表示资源。有向图成环,发生死锁。该图对应上面的代码。
解决死锁四种策略
- 忽略该问题;
- 检测死锁并恢复;
- 仔细分配资源,动态避免死锁;
- 破坏死锁发生条件,避免死锁
忽略该问题
如果死锁发生的概率极低,一年出现一次,为了解决死锁而增加软件硬件带来的问题,反而比死锁本身的问题还大,那么可以直接忽略该问题。
检测死锁并恢复
检测
每种资源只有一个的情况可以通过判断资源和进程构成的有向图是否有环来判定是否有死锁,每种资源有多个的情况可以通过资源矩阵检测是否存在死锁。
恢复
如果检测到存在死锁,那么该如何打破死锁呢。
- 抢占式恢复。
- 回滚恢复。恢复到上一个没有占用资源的状态,进程的部分工作丢失
- 杀死部分进程。从发生死锁的进程中,杀死部分进程,释放占用的资源
仔细分配资源
破坏死锁条件
破坏互斥条件。通过虚拟技术或者其他,使得资源可以同时被多个进程使用。
破坏占有和等待条件。进程在获取资源前,先判断资源是否都可取,一次性获取所有资源。问题在于,进程并不知道它后面会需要哪些资源。比如还可以用trylock,timelock来代替lock避免永久阻塞。
破坏不可抢占。虚拟化技术
避免成环。按照严格的顺序进行加锁,如果不能获取资源就回滚释放占用的部分资源。比如,所有的地方都按照对1加锁,然后对2加锁,就不会成环了。如果线程先对1加锁成功,然后对2加锁,如果加锁失败,就释放资源1。