文章目录
- 一、死锁是什么?
- 二、死锁产生的原因
- 1. 死锁产生的必要条件
- 2. 产生原因
- (1)资源竞争
- (2)可剥夺资源和不可剥夺资源
- (3)竞争不可剥夺资源
- (3)竞争临时资源
- 三、如何避免和解决死锁?
- 1. 预防死锁
- 2. 避免死锁
-
- 3. 检测死锁
- 4. 解除死锁
一、死锁是什么?
死锁,是指多个线程同时被阻塞,其中一个或者全部线程都在等待某个资源,由于资源争夺而造成的一中僵局。若无外力推进,他们都将无法推进。由于无限期的阻塞,程序没有办法进行正常终止。
举个例子~
场景:两个人一起去吃饭,桌上有辣椒和醋,两人都需要加辣椒和醋
A拿起辣椒,B拿起醋
A说:你先把醋给我用,我用完了把辣椒给你
B说:你先把辣椒给我用,我用完了把醋给你
如果两个人互不相让,就会形成死锁。
这里的辣椒和醋就相当于是两把锁。
在死锁中,讨论最多的是哲学家问题
- 有一个桌子,围着4个哲学家。桌子上放着一份菜, 每个哲学家两两之间, 放着一根筷子。
- 每个哲学家只做两件事: 思考人生 或者 吃面条。 思考人生的时候就会放下筷子,吃面条就会拿起左右两边的筷子(先拿起左边, 再拿起右边)
- 如果哲学家发现筷子拿不起来了(被占用了),就会阻塞等待。
- 假设同一时刻, 哲学家同时拿起左手边的筷子, 然后再尝试拿右手的筷子, 就会发现右手的筷子都被占用了。由于哲学家们互不相让,这个时候就形成了死锁。
如下图的情况:每个人拿了左左手的筷子,右手的被占用了
解决办法: 给每个筷子编号,约定让哲学家先拿编号小的,再拿编号大的。而不是,按照左右手来拿。这样,就可以避免死锁。
二、死锁产生的原因
1. 死锁产生的必要条件
- 互斥使用,即当资源被一个线程使用(占有)时,别的线程不能使用。
- 不可剥夺,资源请求者不能强制从资源占有者手中夺取资源,资源只能由资源占有者主动释放。
- 请求和保持,即当资源请求者在请求其他的资源的同时保持对原有资源的占有。
- 循环等待,即存在一个等待队列:P1占有P2的资源,P2占有P3的资源,P3占有P1的资源。这样就形成了环路等待。
当上述四个条件都成立的时候,就会形成死锁。只要打破上述的条件之一,就会
2. 产生原因
(1)资源竞争
当多个进程共享资源,如果资源数目小于进程数,形成资源竞争,造成死锁
(2)可剥夺资源和不可剥夺资源
- 可剥夺资源:当一个进程获得资源后,该资源可被其他进程或者系统剥夺。比如,优先级高的进程剥夺优先级低的进程的资源。
- 不可剥夺资源:当系统把这类资源分配给某进程后,再不能强行收回,只能在进程用完后自行释放,如磁带机、打印机等。
(3)竞争不可剥夺资源
如果系统分配的不可剥夺资源数目小于进程所需,就会造成资源竞争,形成僵局。
举个例子~
系统中有打印机A,磁带机B,进程P1和P2共享。
假如,进程P1获得打印机A,进程P2获得磁带机B。
若P1继续要求磁带机B,由于P2占用,所以阻塞。P2又要求打印机A,但是被P1占用,所以P2阻塞。
P1和P2之间就形成了僵局,两个进程都在等待对方释放自己所需要的资源。
一旦获得资源,不能强制收回,只能等待进程自己释放。
所以,它们又都因不能继续获得自己所需要的资源而不能继续推进,从而也不能释放自己所占有的资源,以致进入死锁状态。
(3)竞争临时资源
临时资源指的就是进程短暂的用过,之后就不再使用了。比如硬件中断、信号、消息、缓冲区内的消息等,它也可能引起死锁。
以下情况也会造成死锁:
- 进程推进顺序不合法
比如,进程P1 P2此时各自获得资源A B,但是,P1需要得到B后再释放资源,P2需要得到A后再释放资源,此时系统不安全。如果再进行推进,就会死锁
三、如何避免和解决死锁?
1. 预防死锁
通过设置限制条件,破坏死锁的必要条件
- 一次性分配所有资源,这样就不会再请求资源了
- 只要有一个资源得不到分配,也不给该进程分配其他资源
- 当某进程获得了部分资源,但得不到其它资源,则释放已占有的资源
- 系统给每类资源赋予一个编号,每一个进程按编号递增的顺序请求资源,释放则相反
2. 避免死锁
在资源分配时,使用某种方法避免系统进入不安全的状态。
银行家算法
首先解释一下安全状态和不安全状态
安全状态:如果存在一个由系统中所有进程构成的安全序列P1,…,Pn,则系统处于安全状态。安全状态一定是没有死锁发生。
不安全状态:不存在一个安全序列,不安全状态不一定导致死锁。
数据结构
- 可利用资源向量Available
是一个含有m个元素的数组,其中的每一个元素代表一类可利用的资源数目。如果Available[j]=K,则表示系统中现有Rj类资源K个。
- 最大需求矩阵Max
这是一个n×m的矩阵,定义了系统中n个进程中的每一个进程对m类资源的最大需求。如果Max[i,j]=K,则表示进程i需要Rj类资源的最大数目为K。
- 分配矩阵Allocation
这是一个n×m的矩阵,它定义了系统中每一类资源当前已分配给每一进程的资源数。如果Allocation[i,j]=K,则表示进程i当前已分得Rj类资源的 数目为K。
- 需求矩阵Need
这是一个n×m的矩阵,用以表示每一个进程尚需的各类资源数。如果Need[i,j]=K,则表示进程i还需要Rj类资源K个。
Need[i,j]=Max[i,j]-Allocation[i,j]
算法描述
-
假设Request是Pi的请求向量,Request[j] = k,代表Pi请求的Rj类资源是k个。
执行如下步骤
-
如果Request[j] <= Need[i,j],执行第二步。否则,出错。
-
如果Request[j] <= Available[j],执行第三步。否则,出错,需要等待。
-
系统试探分配资源,修改相关数据:
Available[j] = Available[j] - Requesti[j];
Allocation[i,j] = Allocation[i,j] + Requesti[j];
Need[i,j] = Need[i,j] - Requesti[j];
-
系统执行安全性检查,如安全,则分配成立;否则试探险性分配作废,系统恢复原状,进程等待。
安全性检查算法
-
设置两个工作向量Work=AVAILABLE;FINISH
-
从进程集合中找到一个满足下述条件的进程,
FINISH==false;
NEED<=Work;
如满足,执行(3)
否则,执行(4)
-
设进程获得资源,可顺利执行,直至完成,从而释放资源。
Work=Work+ALLOCATION;
Finish=true;
返回第二步
-
如所有的进程Finish= true,则表示安全,否则系统不安全
3. 检测死锁
允许系统在运行过程中发生死锁。但是通过系统检测后,能及时地检测出死锁的发生,并精确地确定与死锁有关的进程和资源。
4. 解除死锁
发生死锁的时候,把进程从死锁的状态解脱出来
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)