二十二、死锁

简介: 二十二、死锁

1、死锁问题


首先以一个生活中的例子为例,如下图所示,假设有一座桥,而通过桥的通道只有一条。

cb164c93b37d44f28cbf4dfa1eaba02d.png

当桥的两侧都有车辆需要通过时,由于流量只能在一个方向,所以会发生谁也不能过桥的情况。这种情况与死锁的情形十分类似,如果发生死锁,可以通过一辆车倒退来解决问题(抢占资源和回滚),多数情况下发生死锁可能需要多辆和都一起倒退,这样就由可能导致桥的某一侧的车辆发生饥饿现象。


死锁定义: 一组阻塞的进程持有一种资源等待获取另一个进程所占有的一个资源。i.e., 系统中有两个磁带驱动器,程序P1和程序P2各自占有一个,并且都需要另外一个时,就会发生死锁问题。死锁问题发生的原因在于程序都是并发执行的,各个程序都可以去抢占资源而导致死锁问题。




2、系统模型


在介绍系统模型之前首先介绍资源的相关概念,资源的类型包括: R 1 , R 2 , . . . , R m R_1, R_2, ..., R_m R1,R2,...,Rm,i.e., CPU cycles, memory, I/O devices;每个资源类型 R i R_i Ri都有 W i W_i Wi个实例。


可重复使用的资源: 在一个时间只能一个进程使用且不能被删除;进程获得资源,后来释放由其他进程重复使用;处理器,I/O通道,主和副存储器,设备和数据结构,如文件,数据库和信号量;如果每个进程拥有一个资源并请求其他资源,死锁可能发生。


资源分配图: 一组顶点 V V V和边 E E E的集合;其中 V V V包括以下两种类型:


image.png

所以边         E也包括两种类型:


image.png

02b020e2be3a4423a35d75fb589cb405.png


下图没有死锁现象,因为当进程 P3使用完资源  R3之后,进程 P2便可以执行,之后进程 P1也可以进行执行。

3d5874a7a0d641a29bb62050511f0dd7.png


下图会产生死锁的情况,应为进程和资源之间形成了环路,互相等待对方释放资源,会产生死锁。

d8d490d2361448beb67f2137f29af7d7.png



下图不会产生死锁现象,因为进程 P2和进程  P4执行完毕释放资源R1和 R2之后进程P1和 P3便可以继续执行。

0f2c5991ae504e01ace433de8622df78.png


通过上述可以总结出:如果图中不包括循环,则不会产生死锁;如果图中包括循环,则分为以下两种情况讨论:如果每一个资源类只有一个实例,则会产生死锁;如果每个资源类包括多个实例,则可能产生死锁。




3、死锁特征



死锁可能出现的的四个必要条件:


互斥: 在一个时间只能有一个进程使用资源;


持有并等待: 进程保持至少一个资源正在等待获取其他进程持有的额外资源;


无抢占: 一个资源只能被进程自愿释放,进程已经完成了它的任务之后;


循环等待: 存在等待进程集合 P0,P1,...,Pn,  P0正在等待  P1所占用的资源,  P1正在等待 P2所占用的资源,…,Pn−1正在等待 Pn所占用的资源。




4、死锁处理方式


死锁处理方法包括以下四种:


DeadLock Prevention-死锁预防


DeadLock Avoidance-死锁避免


DeadLock Detection-死锁检测


Recory from DeadLock-死锁恢复



4.1 死锁预防


死锁预防的方法就是针对上述死锁特征的四个必要条件,只要破坏其中一个条件,就构不成死锁。


当破坏条件1时,使资源不互斥的话,那不能满足多进程同时处理同一个资源的准确性要求;


当破坏条件2时,使得进程持有所有需要的资源再执行或者直接不执行,这样处理会使得资源利用率很低,造成饥饿现象;


当破坏条件3时,某个新的进程需要某个旧的进程占用的资源时,直接让只占用没使用的旧进程释放掉资源,这样也会产生一定的饥饿现象;


当破坏条件4时,只要将所有资源类型今次那个排序,并要求每个进程按照资源的顺序进行申请,则可以避免出现环路,但是也会造成一定的资源浪费和额外的排序开销。



4.2 死锁避免


系统在分配给进程资源之前首先判断将资源分配给进程之后是否会产生死锁,如果会产生死锁,则系统不会将资源分配给进程,从而避免死锁的产生。判断是否会产生死锁的方式是判断是否会产生环路,若系统判断将某个资源分配给某个进程之后会形成环路,则系统会认定当前分配为不安全的分配,不会将资源分配给申请资源的进程。

71bfed47f5b1419da3a2b8d96f19e86f.png


银行家算法



银行家算法是一个死锁避免的著名算法,是由Dijkstra在1965年提出的。它以银行借贷系统的分配策略为基础,判断并保证系统的安全运行。


银行家算法的前提条件:首先由多个实例;每个进程都必须能最大限度地利用资源;当一个进程请求一个资源,就不得不等待;当一个进程获得所有的资源,就必须在一段有限的时间释放它们。


银行家算法的数据结构:


n:表示进程数量;


m:表示资源类型数量;


Max(总需求量):是一个 n×m矩阵。如果 Max[i,j]=k,表示进程 P i P_i Pi最多请求资源类型 Rj的 k个实例;


Available(剩余空限量):  长度为m 的 向 量 如果Available[j]=k 表 示 有 k 个 类 型 为 表示有k个类型为 表示有k个类型为R_j$的资源实例可用;


Allocation(已分配量):是一个  n×m矩阵。如果Allocation[i,j]=k,表示进程 Pi当前分配了  k个 jRj实例;


Need(未来需要量) Need(未来需要量):是一个  n×m矩阵。如果 Need[i,j]=k,表示进程 P i P_i Pi当至少需要  k个  Rj实例来完成任务。

Need[i,j]=Max[i,j]−Alllocation[i,j]

Safety State Estamating Algorithm

   work和Finish分别是长度为 m m m和 n n n的向量

   初始化:

work=Available//当前资源剩余的空限量

   F i n i s h [ i ] = f a l s e    f o r    i    i n    { 1 , . . . , n }线程i是否可以结 \qquad 束,即表示线程i是否得到全部所需要的资源


   寻找Need比work小的进程i,其满足以下两个条件:

Finish[i]=false

Need[i]≤work


若没有这种进程i,则转到 Line 12

 work=work+Allocation[i]

Finish[i]=true

   转到 Line 5

  If Finish[i]==true for all i, Then


the system is in a safe state

 

Else


The system is not in a safe state//系统处于非安全状态,不应 \qquad 该将资源交给申请的进程

   E n d End End

Banker’s Algorithm



初始化:Request=request vector for preocess  Pi. If Request[i][j]=k,Then process P i P_i Piwants k instances of resource type Rj,while:

   如果  Request[i]≤Need[i],转到步骤2。否则,提出错误条件,因为进程已经超过了其最大需求。

   如果 Request[i]≤Available,转到步骤3。否则  Pi必须等待,因为资源不可用。

   3.通过修改状态来分配请求资源给 P i P_i Pi:生成一个需要判断状态是否安全的资源分配环境:

Allocation[i]=Allocation[i]+Request[i]Need[i]=Need[i]−Request[i]

   调用 Safety State Estamating Algorithm

   如果返回 safe,则将资源分配给 Pi

   如果返回unsafe, 则 P i P_i Pi必须等待,直到旧的资源分配状态被恢复



4.3 死锁检测


这种方法允许系统进入死锁状态,之后通过死锁检测算法将进入死锁状态的进程进行恢复。死锁检测算法的思路和上述Safety State Estamating Algorithm很类似,其算法流程如下所示:


b534886ffa814b14af6291736fe4f161.png


下面是一个应用死锁检测算法检测出死锁的例子:

86cd3bc26a164e3883d20418ba56eba0.png


4.4 死锁恢复

将所有的死锁进程全部杀死


在一个时间内终止一个进程直到死锁结束


终止进程的顺序应该是:

   按照进程的优先级

   按照进程运行了多久以及需要多少时间才能完成

   进程占用的资源

   进程完成需要的资源

   多少进程需要被终止

   进程是交互还是批处理


还有以一种死锁恢复的方式是资源抢占,选择一个"成本"最小的受害者,之后回滚到一些安全状态。但是会有一定问题,某一个进程可能会一直被选作受害者,造成饥饿现象。


















相关文章
|
2月前
|
NoSQL Java Redis
基本锁的理解(待补充)
可重入锁允许同一线程多次获取同一锁而不致死锁;不可重入锁则不允许递归锁定,连续调用会致死锁。死锁发生在多进程争夺资源导致僵局。读锁允许多线程并发读取,写锁则排他。自旋锁通过循环等待获取锁;共享锁用于只读操作;排它锁用于数据修改;闭锁延迟线程直至状态终止;信号量控制对资源的访问,未获信号量的线程会进入睡眠状态。
|
5月前
|
Java
Java并发编程中的死锁问题及解决方法
【2月更文挑战第11天】 在Java并发编程中,死锁是一个常见但又非常棘手的问题。本文将深入探讨死锁的概念、产生原因以及常见的解决方法,帮助读者更好地理解并发编程中的挑战,并提供实用的解决方案。
84 6
|
2月前
|
Java
【多线程面试题二十二】、 说说你对读写锁的了解
这篇文章讨论了读写锁(ReadWriteLock)的概念和应用场景,强调了读写锁适用于读操作远多于写操作的情况,并介绍了Java中`ReentrantReadWriteLock`实现的读写锁特性,包括公平性选择、可重入和可降级。
|
4月前
|
Python
Python多线程中递归锁如何解决死锁问题的详细阐述
Python多线程中递归锁如何解决死锁问题的详细阐述
|
5月前
|
调度 开发者
探索并发编程中的死锁问题及解决方法
本文将深入探讨并发编程中常见的死锁问题,解释其产生的原因以及对系统造成的影响。同时,将介绍一些常见的死锁解决方法,并提供实际案例进行分析,帮助读者更好地理解并发编程中的死锁现象及应对策略。
|
11月前
|
算法 安全 Java
死锁的原理
之前在学校学习过程中,很少写多进程的代码,虽然操作系统中学过死锁相关的内容,但考试过后也基本就忘记了,后来自己也遇到过有些多进程死锁的情况,再加上看了有些资料,对死锁才算是有了有些深入的理解。
74 0
|
安全
什么是死锁?(把死锁给大家讲明白,知道是什么,为什么用,怎么用)
什么是死锁?(把死锁给大家讲明白,知道是什么,为什么用,怎么用)
83 0
什么是死锁?(把死锁给大家讲明白,知道是什么,为什么用,怎么用)
|
消息中间件 JavaScript 小程序
多线程如何实现事务回滚?一招帮你搞定!
多线程如何实现事务回滚?一招帮你搞定!
多线程如何实现事务回滚?一招帮你搞定!
|
算法 安全 Unix
|
Java
【Java多线程】写一个死锁的例子
【Java多线程】写一个死锁的例子
108 0