Chapter5:死锁

5.1死锁概念

在介绍死锁之前,先来探究一个问题:哲学家就餐问题。五个哲学家围坐在圆桌边,有5支筷子,哲学家在思考、休息、吃饭这三个动作上循环。

我们制定以下规则:

  1.吃饭时使用两支筷子

  2.每次只能取到一支筷子

  3.只取身边的筷子(无论是左还是右)

  4.吃完放下筷子

那么我们可以用文字来模拟以下每个哲学家的行为:

那么我们明显可以看到哲学家就餐问题当中的互斥和同步关系。我们可以给筷子编号,让N号哲学家可以取一支N号筷子(左手边筷子)和一支[(N+4)%5]号筷子(右手边筷子):

我么再以代码的角度去理解这个问题是如何运转的:

现在有趣的现象发生了:这五个哲学家并发执行,也就是说他们可以在同一时刻拿到左手边的筷子。此时每个哲学家都在等待自己右手边的哲学家放下他左手边的筷子,但因为每个哲学家都在这样等,每个哲学家又都不放下自己左手边的筷子,所以这五个哲学家一起阻塞在取右手边筷子,导致谁吃不了饭。这种情况,我们称为发生死锁

这就好比小明同学在外面玩,他妈妈在家里。此时快到饭点了,小明说妈妈做饭了他就回家,妈妈说小明回来了她再做饭。这就导致小明永远回不了家,妈妈永远做不了饭。

死锁的定义:两个或多个执行流无限期地等待永远不会发生的条件,其结果就是导致每个执行流永远阻塞。回到哲学家就餐的话题,每个哲学家都在无限期地等待邻座放下筷子,而邻座没吃完饭之前不会放下筷子,而每个哲学又都只有一支筷子而一直不吃饭,这就是一种死锁状态。

死锁的另一种定义(通常是书籍上写的):在两个或多个执行流中,每个执行流都持有某种资源,但又继续申请其他执行流已经持有的某种资源。此时每个执行流都拥有其运行所需条件的一部分资源,但是又都不够,从而每个执行流都不能向后执行,都陷入阻塞状态。这种状态称为死锁。

5.2死锁的起因

死锁的起因:

  1.系统资源有限:当资源数目不足时,执行流对资源的竞争而可能产生死锁(上面的哲学家就餐问题)

  2.并发执行流的推进顺序不当:执行流请求资源和释放资源的顺序不当时,可能引发死锁(并发执行是不可预见的,这里就不谈了)

  3.不正确的P-V操作也可能会带来死锁

我们把视角切到生产者消费者问题:

关于死锁的一些结论:

  1.导致死锁的执行流至少是两个

  2.导致死锁的执行流至少有两个已经占有资源(只差一部分资源即可向后执行)

  3.导致死锁的执行流都在等待资源

  4.导致死锁的执行流可以是当前系统中所有执行流的子集(假设有8个执行流,导致死锁的执行流可以是2个、3个、4个...8个)

5.3预防死锁的策略

死锁的必要条件:

  1.互斥条件:执行流之间互斥使用资源

  2.不剥夺条件:执行流在自己释放资源之前,其他执行流不能强行剥夺当前执行流占有的资源

  3.部分分配条件:执行流边运行边申请资源,临时需要临时分配。区别于全部分配,全部分配不可能导致死锁(例如哲学家吃饭问题,一开始只要让一个哲学家或两个哲学家先吃饭,就不可能导致死锁)

  4.环路条件:多个执行流构成环路,环路中的每个执行流占用的资源被前一个执行流申请,而自己需要的另一部分资源被下一个执行流占用

只有这四个条件同时成立,才会导致死锁。也就是说,只要破坏四个条件中的一个,就不可能导致死锁。例如哲学家就餐问题,我们只需要限定最多4人同时吃饭,也就相当于破坏环路条件了(因为必定有一人不需要等待邻座的筷子)。

解决死锁的策略:

  1.预防死锁:通过设置某些限制条件,破坏死锁四个必要条件中的任意一个,就可以防止死锁。但是能,要破坏互斥条件,难;破坏不剥夺条件,代价大;破坏部分分配条件,需要使用预先静态分配(这就会导致给每个执行流百分之百的资源,但执行流可能只使用其中百分之一);破坏环路条件,可以使用有序资源分配。预防死锁的策略较易实现,在早期被广泛使用。它被淘汰的原因在于限制太过严格,导致资源利用率和吞吐量降低。

  2.避免死锁:不事先采用限制去破坏死锁的必要条件,而是在资源分配过程中,用某种算法去评估分配的资源会不会让系统(多个执行流之间)进入死锁状态,如果死锁,就不分配此次资源,从而避免死锁的发生。典型的算法就是银行家算法,同时它是一个很难的算法。避免死锁的策略虽然只需要较弱的限制条件,并且可以获得较高的资源利用率和吞吐量,但是缺点显而易见,要实现太困难了。

  3.检测死锁和恢复死锁:允许死锁发生,但可以通过检测机制及时检测出死锁状态,并精确确定与死锁有关的执行流和资源,然后采取适当措施,将已发生的死锁清楚,让执行流"解放"。缺点:检测方法复杂,难度高;恢复死锁的方法依靠人工,即使检测到死锁的发生,也需要人工去撤销一些执行流然后再重新分配资源。

预先静态分配:

  1.特点:

    1)执行可能被延迟:所需资源不能全部满足时(预先分配的资源万一不够)

    2)应用开销增大:运行前要估算资源的需求

    3)资源利用率低:资源被占而不用(给某一执行流分配百分之百的资源,但它只占用百分之一)

  2.改进:资源分配的单位由执行流改为程序步

有序资源分配:

  1.目的:破坏环路条件,使得环路无法构成

  2.策略:系统(多个执行流)中的每个资源分配有唯一的序号,执行流每次申请资源时只能申请序号更大的资源。如果执行流已经占有资源的序号为M,那么下一次只能申请序号大于M的资源,而不能申请序号小于或等于M的资源。

  3.资源分配策略:分配资源时检查资源序号是否符合递增规定。若不符合,则拒绝申请,并将申请资源的执行流撤销;若符合且资源可用,那么便予以分配;若符合但资源不可用,当前申请资源的执行流陷入阻塞。

Windows和Linux采用的死锁解决方案非常有意思,我们把它称为鸵鸟策略——我知道有死锁,但我选择无视。

思考题:

1.在Linux或Windows的实际应用中,用户常说的“死机”或“宕机”或“程序卡住”或“系统卡住,键鼠没有任何响应”与本章的“死锁”是同一问题吗?

不是。程序自己崩溃是单一的,不符合死锁的条件。

posted @ 2023-04-14 16:20  小龙向钱进  阅读(38)  评论(0编辑  收藏  举报