死锁的定义、产生原因、必要条件、避免死锁和解除死锁的方法

本文详细解释了死锁的概念、产生的原因及必要条件,并介绍了避免和解除死锁的方法。

1. 死锁:如果一组进程中的每一个进程都在等待仅由该组进程中的其它进程才能引发的事件,那么该组进程是死锁的。



2.产生死锁的原因:

(1)竞争不可抢占性资源


(2)竞争可消耗资源:

   当系统中供多个进程共享的资源如打印机,公用队列等,其数目不足以满足诸进程的需要时,会引起诸进程对资源的竞争而产生死锁。


(3)进程推进顺序不当:

   进程在运行过程中,请求和释放资源的顺序不当,也同样会导致产生进程死锁。


如果系统资源充足,进程的资源请求都能够得到满足,死锁出现的可能性就很低,否则就会因争夺有限的资源而陷入死锁。其次,进程运行推进顺序与速度不同,也可能产生死锁。一个线程也可引起死锁。



3.产生死锁的四个必要条件:

(1) 互斥条件:一个资源每次只能被一个进程使用。

(2) 请求和保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。

(3) 不可抢占条件:进程已获得的资源,在末使用完之前,不能强行剥夺,只能在进程使用完时由自己释放。

(4) 循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。


 这四个条件是死锁的必要条件,只要系统发生死锁,这些条件必然成立,而只要上述条件之一不满足,就不会发生死锁。因此可以写下如下的预防死锁的方法。



4.避免死锁的方法:

(1)破坏“互斥”条件:就是在系统里取消互斥。若资源不被一个进程独占使用,那么死锁是肯定不会发生的。但一般“互斥”条件是无法破坏的。因此,在死锁预防里主要是破坏其他三个必要条件,而不去涉及破坏“互斥”条件。


(2)破坏“请求和保持”条件:在系统中不允许进程在已获得某种资源的情况下,申请其他资源。即要想出一个办法,阻止进程在持有资源的同时申请其他资源:


   方法一:所有进程在运行之前,必须一次性地申请在整个运行过程中所需的全部资源。这样,该进程在整个运行期间,便不会再提出资源请求,从而破坏了“请求”条件。系统在分配资源时,只要有一种资源不能满足进程的要求,即使其它所需的各资源都空闲也不分配给该进程,而让该进程等待。由于该进程在等待期间未占有任何资源,于是破坏了“保持”条件。该方法优点:简单、易行且安全。缺点:a.资源被严重浪费,严重恶化了资源的利用率。b.使进程经常会发生饥饿现象。


   方法二:要求每个进程提出新的资源申请前,释放它所占有的资源。这样,一个进程在需要资源S时,须先把它先前占有的资源R释放掉,然后才能提出对S的申请,即使它可能很快又要用到资源R。


(3)破坏“不可抢占”条件:允许对资源实行抢夺。
方法一:如果占有某些资源的一个进程进行进一步资源请求被拒绝,则该进程必须释放它最初占有的资源,如果有必要,可再次请求这些资源和另外的资源。
方法二:如果一个进程请求当前被另一个进程占有的一个资源,则操作系统可以抢占另一个进程,要求它释放资源。只有在任意两个进程的优先级都不相同的条件下,该方法才能预防死锁。


(4)破坏“循环等待”条件:将系统中的所有资源统一编号,进程可在任何时刻提出资源申请,但所有申请必须按照资源的编号顺序(升序)提出。这样做就能保证系统不出现死锁。

利用银行家算法避免死锁:

银行家算法:

设进程i提出请求Request[j],则银行家算法按如下规则进行判断。

(1) 如果Request[j]≤Need[i,j],则转向(2),否则认为出错,因为它所需要的资源数已超过它所宣布的最大值。

(2) 如果Request[j]≤Available[j],则转向(3);否则表示尚无足够资源,Pi需等待。

(3) 假设进程i的申请已获批准,于是修改系统状态:

Available[j]=Available[j]-Request[i]

Allocation[i,j]=Allocation[i,j]+Request[j]

Need[i,j]=Need[i,j]-Request[j]

(4)系统执行安全性检查,如安全,则分配成立;否则试探险性分配作废,系统恢复原状,进程等待。

安全性算法:

(1) 设置两个工作向量Work=Available;Finish[i]=False

(2) 从进程集合中找到一个满足下述条件的进程,

     Finish [i]=False;

     Need[i,j]≤Work[j];

     如找到,执行(3);否则,执行(4)

(3) 设进程获得资源,可顺利执行,直至完成,从而释放资源。

    Work[j]=Work[j]+Allocation[i,j];

    Finish[i]=True;

    go to step 2;

(4) 如所有的进程Finish[i]=true,则表示安全;否则系统不安全。



5.死锁的解除:

一旦检测出死锁,就应立即釆取相应的措施,以解除死锁。死锁解除的主要两种方法:

1) 抢占资源。从一个或多个进程中抢占足够数量的资源,分配给死锁进程,以解除死锁状态。

2) 终止(或撤销)进程。终止(或撤销)系统中的一个或多个死锁进程,直至打破循环环路,使系统从死锁状态解脱出来。

总结:

       一般情况下,如果同一个线程先后两次调用lock,在第二次调用时,由于锁已经被占用,该线程会挂起等待别的线程释放锁,然而锁正是被自己占用着的,该线程又被挂起而没有机会释放锁,因此就永远处于挂起等待状态了,这叫做死锁(Deadlock)。另⼀一种典型的死锁情形是这样:线程A获得了锁1,线程B获得了锁2,这时线程A调⽤用lock试图获得锁2,结果是需要挂起等待线程B释放锁2,而这时线程B也调⽤用lock试图获得锁1,结果是需要挂起等待线程A释放锁1,于是线程A和B都永远处于挂起状态了。

注意:

      写程序时应该尽量避免同时获得多个锁,如果一定有必要这么做,则有一个原则:如果所有线程在需要多个锁时都按相同的先后顺序(常见的是按Mutex变量的地址顺序)获得锁,则不会出现死锁。比如一个程序中用到锁1、锁2、锁3,它们所对应的Mutex变量的地址是锁1<锁2<锁3,那么所有线程在需要同时获得2个或3个锁时都应该按锁1、锁2、锁3的顺序获得。如果要为所有的锁确定一个先后顺序比较困难,则应pthread_mutex_trylock调用代替pthread_mutex_lock 调用,以免死锁。


  转载自:http://blog.youkuaiyun.com/yanxiaolx/article/details/51944048

### 死锁的四个必要条件 死锁产生需要同时满足以下四个必要条件: 1. **互斥**:一次只有一个进程可以使用一个资源。某些资源本质上是不可共享的,因此互斥是资源分配的基本特性之一[^1]。 2. **占有且等待**:一个进程在等待其他资源时,继续占有已经分配给它的资源。这种情况会导致资源的低效利用,并可能引发死锁[^1]。 3. **不可抢占**:资源不能被强制从一个进程中剥夺。资源只能在进程使用完成后主动释放。 4. **循环等待**:存在一个闭合的进程链,每个进程至少占有此链中下一个进程所需的一个资源。这种循环依赖关系是死锁的直接原因[^2]。 --- ### 死锁的预防方法 死锁预防的目标是通过破坏上述四个必要条件中的至少一个来防止死锁的发生。 1. **防止互斥**:由于互斥是资源的固有属性,通常无法避免。因此,这一条件一般不作为预防的重点。 2. **防止“占有且等待”**:要求进程在开始执行前一次性请求所有需要的资源,直到所有资源都满足后才运行。这种方法虽然有效,但可能导致资源利用率低下[^2]。 3. **防止“不可抢占”**:如果一个进程的资源请求无法满足,它可以释放已占有的资源;或者操作系统可以强制其他进程释放资源。这种方法需要保存资源的状态以便恢复。 4. **防止循环等待**:通过定义资源请求的顺序规则,例如要求进程按照资源编号的递增顺序申请资源,从而避免形成循环依赖。这种方法可能导致资源请求的灵活性下降。 --- ### 死锁避免 死锁避免是一种动态策略,通过在资源分配时进行检查来确保系统不会进入不安全状态。 - **资源分配拒绝**:如果一个进程的资源请求会导致系统进入不安全状态,则拒绝该请求。例如,银行家算法通过计算资源分配后的系统状态来决定是否分配资源。 - **进程启动拒绝**:如果新进程的启动可能导致死锁,则拒绝其启动。这种方法通常用于系统初始化阶段[^1]。 --- ### 死锁检测解除 死锁检测是一种事后处理机制,适用于那些未采取预防或避免措施的系统。 - **检测机制**:系统定期运行死锁检测算法,通过资源分配图或等待图来识别是否存在死锁。如果发现死锁,则采取相应的解除措施[^1]。 - **解除方法**: - **资源抢占**:强制从某些进程中剥夺资源,并将其分配给死锁进程。 - **进程终止**:终止一个或多个死锁进程以打破循环。 - **回滚**:将系统状态回滚到某个检查点,并重新执行进程。 --- ### 银行家算法示例 银行家算法是一种经典的死锁避免算法。它通过维护系统的安全状态来决定是否分配资源。以下是一个简化的银行家算法实现示例(Python): ```python def is_safe_state(available, max_need, allocation): work = available[:] finish = [False] * len(max_need) while True: found = False for i in range(len(max_need)): if not finish[i]: can_allocate = True for j in range(len(available)): if max_need[i][j] - allocation[i][j] > work[j]: can_allocate = False break if can_allocate: for j in range(len(available)): work[j] += allocation[i][j] finish[i] = True found = True if not found: break return all(finish) # 示例输入 available = [3, 3, 2] max_need = [ [7, 5, 3], [3, 2, 2], [9, 0, 2], [2, 2, 2], [4, 3, 3] ] allocation = [ [0, 1, 0], [2, 0, 0], [3, 0, 2], [2, 1, 1], [0, 0, 2] ] # 检查是否处于安全状态 if is_safe_state(available, max_need, allocation): print("系统处于安全状态。") else: print("系统处于不安全状态,可能死锁。") ``` --- ### 总结 死锁产生需要满足互斥、占有且等待、不可抢占循环等待四个必要条件。通过破坏这些条件可以预防死锁;通过动态检查资源分配可以避免死锁;而死锁检测解除则用于事后处理。银行家算法是死锁避免中的经典方法,能够有效防止系统进入不安全状态。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值