死锁的四个必要条件及处理死锁

来源:互联网 发布:刺客信条 mac 编辑:程序博客网 时间:2024/05/22 10:29
如果一个进程集合里面的每个进程都在等待只能由这个集合中的其他一个进程(包括他自身)才能引发的事件,这种情况就是死锁。

这个定义可能有点拗口,下面用一个简单例子说明。
  资源A、B进程C、D描述如下:
  资源A和资源B,都是不可剥夺资源,
  现在进程C已经申请了资源A,进程D也申请了资源B,
  进程C接下来的操作需要用到资源B,而进程D恰好也在申请资源A,
  进程C、D都得不到接下来的资源,那么就引发了死锁。
然后套用回去定义:如果一个进程集合里面(进程C和进 程D)的每个进程(进程C和进程D)都在等待只能由这个集合中的其他一个进程(对于进程C,他在等进程D;对于进程D,他在等进程C)才能引发的事件(释放相应资源)。

这里的资源包括了软的资源(代码块)和硬的资源(例如扫描仪)。资源一般可以分两种:可剥夺资源(Preemptable)和不可剥夺资源 (Nonpreemptable)。一般来说对于由可剥夺资源引起的死锁可以由系统的重新分配资源来解决,所以一般来说大家说的死锁都是由于不可剥夺资源 所引起的。

死锁的四个必要条件

(1) 互斥条件:一个资源每次只能被一个进程使用。
(2) 请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。
(3) 不剥夺条件:进程已获得的资源,在末使用完之前,不能强行剥夺。
(4) 循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。 

处理死锁的策略

1.忽略该问题。例如鸵鸟算法,该算法可以应用在极少发生死锁的的情况下。为什么叫鸵鸟算法呢,因为传说中鸵鸟看到危险就把头埋在地底下,可能鸵鸟觉得看不到危险也就没危险了吧。跟掩耳盗铃有点像。
2.检测死锁并且恢复。
3.仔细地对资源进行动态分配,以避免死锁。
4.通过破除死锁四个必要条件之一,来防止死锁

根据死锁发生的必要条件,下面两个函数在多线程环境下则不会发送死锁(条件2不满足)

void func1()

{

lockA.Lock();

...// 临界区A,不包括lockB或lockC的锁调用

lockA.UnLock();


lockB.Lock();

...// 临界区B,不包括lockA或lockC的锁调用

lockB.UnLock();


lockC.Lock();

...// 临界区C,不包括locka或lockC的锁调用

lockC.UnLock();

}


void func1() // 里面也包括lockA、lockB、lockC的调用,但互相之间不潜逃,但顺序不一定按照lockA、lockB、lockC的顺序进行(可以是B、A、C等...)

{
       lockB.Lock();

...// 临界区B,不包括lockA或lockC的锁调用

  lockB.UnLock();
 

lockA.Lock();

...// 临界区A,不包括lockB或lockC的锁调用

lockA.UnLock();


lockC.Lock();

...// 临界区C,不包括locka或lockC的锁调用

lockC.UnLock();

}

对于嵌套锁来说,
必须保证按某种顺序获取锁

增加了一个访问资源的间接层,尽量避免高层代码控制资源的获取.另外,因为为每个资源类型实现间接层,避免了一个锁控制访问多个资源的情况.对于需要获取多个资源的,在更高一层把这种获取逻辑抽取出来,提供一个统一的资源获取逻辑,而在实现内部,确保有序获取资源,在算法上避免死锁.
0 0