Linux - 死锁现象

一、死锁的概念:

  1、死锁的现象描述:

    在很多应用中,需要一个进程排他性的访问若干种资源而不是一种。例如,两个进程准备分别将扫描的文档记录到CD上。进程A请求使用扫描仪,

并被授权使用。但进程B首先请求CD刻录机,也被授权使用。这时,A请求使用CD刻录机,但这个请求在B释放CD刻录机前会被拒绝。但是,进程B非但

不会释放CD刻录机,还去请求扫描仪。这时,两个进程僵持不下,都被阻塞,并一直处于这样的状态。这种状况就叫做死锁(deadlock)。

  2、死锁的规范定义:

    如果一个进程集合中的每个进程都在等待只能由该进程集合中的其他进程才能引发的事件,那么,该进程集合是死锁的。

二、产生死锁的四个必要条件:

  1、互斥条件。每个资源要么意境分配给了一个进程,要么就是可用的。

  2、占有和等待条件。已经得到可某个资源的进程可以在请求新的资源。

  3、不可抢占条件。已经分配给一个进程的资源不能强制性地被抢占,它只能占有它的进程显式的释放。

  4、循环等待条件。死锁发生时,系统中一定有两个或两个以上的进程组成的一条环路,该环路中的每一个进程都在等待着下一个进程所占有的资源。

  死锁发生时,以上四个条件一定是同时满足的。如果有任意一条不成立,那么死锁就不会发生。

三、如何有效地预防死锁

  预防死锁的根本办法就是要使死锁产生的4个必要条件之一不存在。下面来分析一下破坏这些条件的可能性。

  1、破坏互斥条件

  破坏互斥条件即允许多个进程同时访问资源。由于多数资源的必须互斥访问这一固有特性不能改变,因此,死锁的预防通过破坏这个必要条件实现在

很多场合是行不通的。例如,打印机资源必须互斥使用,否则几个进程同时使用,每个进程各打印一行,这种输出信息的方式显然是不能被用户接受的。

  2、破坏占有和等待条件

  采用资源静态分配法可破坏这一条件,该方法是指在进程运行前,一次性地_请分配它运行所需的全部资源。若系统有足够的资源分配给某一进程,则

一次性地将其所需资源分配给该进程,这样,在进程运行期间便不会再提出任何资源请求,从而使等待条件不成立。如果分配时有一种资源要求不能满足,

则进程需要的其他资源也先不分配给进程,从而避免进程在等待期间占用任何资源,破坏了占用条件,从而避免死锁的发生。

  优缺点:该方法控制简单且容易实现,但由于进程运行期间对所需资源的全部占用,使得某些使用时间很短的资源被长时间占用,这样会严重影响系统

资源的充分利用,导致资源利用率降低,同吋也影响到未获得全部资源的进程推迟运行。

  3、破坏不剥夺条件

  采用剥夺式控制方法可以破坏该条件,该方法是使一个已保持了某些资源的进程,由于新的资源要求目前得不到满足,它必须先暂时释放巳保持的所有资

源(一种剥夺式),然后去等待,以后再一起向系统提出巾请,这样也能防止死锁。

  优缺点:这种方法实现起来相对较难,为了保护进程自动放弃资源的现场以及后来的再次恢复,需要付出高昂的代价,并且这种方法只适用于处理机和存

储器资源,对其他资源,此法不宜使用。

  4、破坏循环等待条件

  采用资源顺序分配法可破坏该条件。这种分配方法的基本思想是:把系统的全部资源分成多个层次,一个进程得到某一层的一个资源后,它只能再_请较

高一层的资源;当一个进程要释放某层的一个资源时,必须先释放所占有的较高层的资源;当一个进程获得了某一层的一个资源后,它想再申请该层中的另一个

资源,就必须先释放在该层中巳占有的资源。或者说,进程释放资源的顺序是按照中请资源的相反顺序进行的。这样可以预防循环等待现象的发生,因此不会

发生死锁。使用该方法要特別注意的问题是对资源所处层次的安排。在通常情况下,把各进程经常用到的、比较普遍的资源安排在较低的层次上,把重要且相

对匮乏的资源安排在较高的层次上,以便实现对各资源的最大限度的利用。

  优缺点:该方法相对于前面介绍的方法,在资源利用率和系统吞吐量上都有明显的改善。但也存在一些缺陷:

  (1)低层次的资源必须在进程请求分配髙层次的资源之前提前申请,这对于暂时不需使用的低层次资源来说,会因空闲等待而产生浪费。

  (2)各类设备的资源层次一经设定,便不能经常随意改动,这就限制了新类型设备的增加。

  (3)各资源的层次是按照大多数进程使用资源的顺序设置的。对于资源使用与此层次相闪配的进程,资源能得到有效的利用,否则,资源的浪费现象将

仍然存在。

四、如何解除死锁

  死锁的解除实质上就是如何让释放资源的进程能够继续运行.

  为了解除死锁就要剥夺资源,此时,需要考虑一下几个问题:

  (1)    选择一个牺牲进程,即要剥夺哪个进程的哪些资源

  (2)    重新运行或回到某一点开始继续运行.若从一个进程那里剥夺了资源,要为该进程作些什么事情?显然,这个进程是不能继续正常执行了.必须将该进程

回到七点或某个状态,以后在重新开始执行.令进程夭折的方法虽然简单,但代价大;而更有效的方法是只让它退回到足以解除死锁的地步即可.那么,问题转换成进

程回退的状态由什么组成?怎样才能更方便的确定该状态,这就要求系统保持根多的有关进程运行的信息.

  (3)    怎样保证不发生”饿死”现象,即如何保证并不总是剥夺同一进程的资源,而导致该进程处于”饥饿”状态.

  (4)    “最小代价”,即最经济合算的算法,使得进程回退带来的开销最小.但是,”最小开销”是很不精确的,进程重新运行的开销包括很多因素

    (a)    进程的优先级

    (b)    进程已经运行了多长时间了,该浸沉完成其任务还需要多长时间

    (c)    该进程使用的资源种类和数量?这些资源能简单的剥夺吗?

    (d)    为完成任务,进程还需要多少资源?

    (e)    有多少进程要被撤销

    (f)    该进程被重新启动运行的次数.

  一旦决定一个进程必须回退,就一定要确定这个进程回退多少.最简单的方法是从头来,让其重新运行,这将会使一个进程的工作”前功尽弃”.

  死锁解除法可归纳为两大类

  1. 剥夺资源

    使用挂起/激活机制挂起一些进程,剥夺它们占有的资源给死锁进程,以解除死锁,待以后条件满足时,在激活被挂起的进程.

    由于死锁是由进程竞争资源而引起的,所以,可以从一些进程那里强行剥夺足够数量的资源分配给死锁进程,以解除死锁状态.剥夺的顺序可以是以话费

最小资源数为依据.每次剥夺后,需要再次调用死锁检测算法,资源被剥夺的进程为了在得到该资源,必须重新提出申请,为了安全的释放资源,该进程就必须

返回到分配资源前的某一点.金昌使用的方法有:

  (1)    欢迎算法,即恢复计算结果和状态.

  (2)    建立检查点主要是用来恢复分配前的状态.这种发放对实时系统和长时间运行的数据处理来说是一种常用技术.在实时系统中,经常在某些程序地址插

入检  查的程序段,即采用检查点的技术来验证系统的正确性,如发现故障,可从检查点重新启动.因此,在有些实时系统中,一旦发现死锁,可以在释放某进程的资

源后,从检查点重新启动.

  2.撤销进程

    撤销死锁进程.将它们占有的资源分配给另一些死锁进程,知道死锁解除为止.

    可以撤销所有死锁进程,或者琢个撤销死锁进程,美撤销一个进程就检测死锁是否继续存在,若已没有死锁,就停止进程的撤销.

    如果按照某种顺序依次撤销已死锁的进程,知道获得为解除死锁所需要的足够可用的资源为止,那么在极端情况下,这种发放可能造成除一个死锁进程外,

  其余的死锁进程全部被撤销的局面.

    按照什么原则撤销进程?较实用而又简单的方法是撤销那些代价最小的进程,或者使撤销进程的数目最小.一下几点可作为衡量撤销代价的标准:

    (1)    进程优先数,即被撤销进程的优先数.

    (2)    进程类的外部代价.不同类型的进程可以规定出各自的撤销代价.系统可根据这些规定,撤销代价最小的进程,达到解除死锁的目的.

    (3)    运行代价,即重新启动进程并运行到当前撤销点所需要的代价.这一点可由系统记帐程序给出

    优缺点:撤销发的优点是简单明了,但有时可能不分青红皂白的撤销一些甚至不影响死锁的进程

时间: 2024-12-27 17:00:01

Linux - 死锁现象的相关文章

Linux死锁检测-Lockdep

专题:Linux内存管理专题 关键词:LockDep.spinlock.mutex. lockdep是内核提供协助发现死锁问题的功能. 本文首先介绍何为lockdep,然后如何在内核使能lockdep,并简单分析内核lockdep相关代码. 最后构造不同死锁用例,并分析如何根据lockdep输出发现问题根源. 1. Lockdep介绍 死锁是指两个或多个进程因争夺资源而造成的互相等待的现象. 常见的死锁有如下两种: 递归死锁:中断等延迟操作中使用了锁,和外面的锁构成了递归死锁. AB-BA死锁:

linux死锁检测的一种思路【转】

转自:http://blog.csdn.net/zdy0_2004/article/details/44652323 linux死锁检测的一种思路 http://www.cnblogs.com/mumuxinfei/p/4365697.html 前言: 上一篇博文讲述了pstack的使用和原理. 和jstack一样, pstack能获取进程的线程堆栈快照, 方便检验和性能评估. 但jstack功能更加的强大, 它能对潜在的死锁予以提示, 而pstack只提供了线索, 需要gdb进一步的确定. 那

Thking in Java---从哲学家就餐问题看死锁现象

我们知道一个对象可以有synchronized方法或其他形式的加锁机制来防止别的线程在互斥还没释放的时候就访问这个对象.而且我们知道线程是会变成阻塞状态的(挂起),所以有时候就会发生死锁的情况:某个任务在等待另一个任务,而后者又在等待其它任务,这样一直下去,知道这个链条下的任务又在等待第一个任务释放锁,这样就形成了一个任务之间相互等待的连续循环,没有任务可以继续的情况.死锁的最大问题在于它发生的几率非常小,并不是我们一运行程序它就死锁了,而是会不知道那个时候程序就死锁了并且我们很难重现当时出现死

死锁现象与解决方案,开启线程的2种方式,守护线程,线程VS进程,线程互斥锁,信号量

死锁现象与解决方案 from threading import Thread,Lock,active_count import time mutexA=Lock() # 锁1 mutexB=Lock() # 锁2 class Mythread(Thread): def run(self): self.f1() self.f2() def f1(self): mutexA.acquire() print('%s 拿到A锁' %self.name) mutexB.acquire() print('%

同步函数死锁现象

多线程:一个进程中有多个线程可以同时执行任务 多线程的好处: 1.解决一个进程中可以同时执行多个任务的问题. 2.提高了资源利用率 多线程的弊端: 1.增加了CPU的负担 2.降低了一个进程中线程的执行概率 3.出现了线程安全问题 4.会引发死锁现象 自定义线程的实现方式: 方式一: 1.自定义一个类继承Thread类. 2.重写Thread类的run方法,把自定义线程的任务代码写在run方法上 3.创建Thread的子类对象,并且调用start方法启动一个线程 线程安全问题出现的根本原因: 1

死锁现象与递归锁

一 死锁现象 所谓死锁: 是指两个或两个以上的进程或线程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去.此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程称为死锁进程,如下就是死锁 from threading import Thread,Lock import time mutexA=Lock() mutexB=Lock() class MyThread(Thread): def run(self): self.func1() self.f

python并发编程之线程(创建线程,锁(死锁现象,递归锁),GIL锁)

什么是线程 进程:资源分配单位 线程:cpu执行单位(实体),每一个py文件中就是一个进程,一个进程中至少有一个线程 线程的两种创建方式: 一 from multiprocessing import Process def f1(n): print(n,'号线程') if __name__ == '__main__': t1 = Thread(target=f1,args=(1,)) t1.start() print('主线程')  二 from threading import Thread

python 并发编程 多线程 死锁现象与递归锁

一 死锁现象 所谓死锁: 是指两个或两个以上的进程或线程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去.此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程称为死锁进程,如下就是死锁 from threading import Thread from threading import Lock import time # 实例化两把不同的锁 mutexA = Lock() mutexB = Lock() class MyThread(Threa

2-7 死锁现象和递归锁

一 死锁现象 所谓死锁: 是指两个或两个以上的进程或线程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去.此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程称为死锁进程,如下就是死锁 from threading import Thread,Lock import time mutexA=Lock() mutexB=Lock() class MyThread(Thread): def run(self): self.func1() self.f