多线程之死锁
介绍
死锁是指两个或两个以上进程(在运行的过程中因争夺资源而造成的一种僵局),若无外力作用,这些线程,进程都将无法向前推进。
- 参与死锁的进程(线程)至少为2个
- 参与死锁的进程(线程)均等待资源
- 参与死锁的进程(线程)至少有2个已经占有资源
- 死锁进程是系统中当前进程集合的一个子集
- 死锁会浪费大量系统资源,甚至导致系统崩溃
资源
所有的死锁都是对资源的争夺造成的,资源是一切的罪魁祸首。
永久资源与临时资源
永久资源
永久资源可以被多次使用,如所有硬件。
- 只能分配给一个进程使用,不允许多个进程共享
- 进程使用时,需按照请求资源、使用资源、释放资源的顺序
- 这种资源的数量是固定的,运行期间,不能创建,也不能销毁
临时资源
是在运行期间动态创建和销毁的资源。
- 数量在运行期间是不断变化的,有可能为0
- 在运行过程中,可以不断的创建这种资源,将它们放入缓冲区,增加资源数量
- 也可以在运行过程中,请求几个临时资源,用于运行中的消耗
一般由生产者进程产生,消费者进程消耗,如何用于通信的消息。
可抢占资源和不可抢占资源
可抢占资源
可抢占资源指某进程在获得这类资源后,该类资源可以被其他进程或系统抢占,也就是大家共享,这类资源不会引起死锁。比如CPU和内存。
不可抢占资源
一旦系统将某资源分配给该进程后,就不能将其强行收回,只能在进程使用完后自己释放。比如打印机。
死锁原因
- 竞争不可抢占资源引起死锁
通常系统中的不可抢占资源,其数量不足以满足同时运行,使得在运行过程中,会因资源抢占而进入僵局,造成死锁。
- 竞争可消耗资源引起死锁
- 进程推进顺序不当引起死锁
运行过程中,请求和释放资源的顺序不科学,也会造成死锁,我等你,你等我的情况。
信号量使用不当也会死锁,进程间彼此相互等待对方发来的消息,结果也会使得这 些进程间无法继续向前推进。
死锁条件
互斥条件
运行的进程对它所分配的资源进行排他性控制,在一段时间内某资源仅为一个进程所占用。此时若有其他进程线程来请求资源,则请求的进程线程只能等待。
不可剥夺条件
所获得的资源,已经占用的资源,不能被其他进程强行夺走,只能由自己主动释放。
请求与保持
进程已经保持占用了至少一个资源,但又提出了新的资源请求,而该资源已经被其他进程占有,此时进程请求被阻塞,但对自己已获得资源保持占用。
循环等待
存在进程资源间的循环等待链。
处理死锁
- 预防死锁:通过设置某些限制条件,去破坏产生死锁的四个条件的一个或几个。
- 避免死锁:在资源的动态分配过程中,用某种方法防止系统进入不安全状态,从而避免死锁发生。
- 检测死锁:允许系统在运行过程中发生死锁,但可设置检测机构及时检测死锁的发生,并采取适当措施加以清除。
- 解除死锁:当检测出死锁后,便采取适当措施将进程从死锁状态中解脱出来。
预防死锁
破坏互斥条件
就是在系统里取消互斥。若资源不被一个进程独占使用,那么死锁是肯定不会发生的。
实际情况中,互斥条件一般不能也无法被破环,否则会造成结果不可再现。
破环不可抢占条件
就是允许对资源实行抢夺。
- 如果占有某些资源的一个进程进行进一步资源请求被拒绝,则该进程必须释放它最初占有的资源,如果有必要,可再次请求这些资源和另外的资源。
- 如果一个进程请求当前被另一个进程占有的一个资源,则操作系统可以抢占另一个进程,要求它释放资源。只有在任意两个进程的优先级都不相同的条件下,方法二才能预防死锁。
破环请求与保持条件
就是在系统中不允许进程在已获得某种资源的情况下,申请其他资源。即要想出一个办法,阻止进程在持有资源的同时申请其他资源。
- 创建进程时,要求它申请所需的全部资源,系统或满足其所有要求,或什么也不给它。这是所谓的 “ 一次性分配”方案。
- 要求每个进程提出新的资源申请前,释放它所占有的资源。这样,一个进程在需要资源S时,须先把它先前占有的资源R释放掉,然后才能提出对S的申请,即使它可能很快又要用到资源R。
破环循环等待条件
破坏“循环等待”条件的一种方法,是将系统中的所有资源统一编号,进程可在任何时刻提出资源申请,但所有申请必须按照资源的编号顺序(升序)提出。这样做就能保证系统不出现死锁。
避免死锁
合理规划资源,在系统资源,进程调度等方面,设计让死锁条件无法满足,避免进程永久占据系统资源或在等待条件下占用资源,从而防止死锁。
预防死锁和避免死锁的区别:预防死锁是设法至少破坏产生死锁的四个必要条件之一,严格的防止死锁的出现,而避免死锁则不那么严格的限制产生死锁的必要条件的存在。因为即使死锁的必要条件存在,也不一定发生死锁。避免死锁是在系统运行过程中注意避免死锁的最终发生。
避免死锁的方法
- 有序资源分配法
- 银行家算法
避免死锁的技术
- 加锁顺序
- 加锁时限
- 死锁检测
检测死锁
死锁检测与恢复是指系统设有专门的机构,当死锁发生时,该机构能够检测到死锁发生的位置和原因,并能通过外力破坏死锁发生的必要条件,从而使得并发进程从死锁状态中恢复出来。
解除死锁
死锁解除的方法有:
- 资源剥夺法:挂起某些死锁进程,并抢占它的资源,将这些资源分配给其他的死锁进程。但应防止被挂起的进程长时间得不到资源,而处于资源匮乏的状态。
- 撤销进程法:强制撤销部分、甚至全部死锁进程并剥夺这些进程的资源。撤销的原则可以按进程优先级和撤销进程代价的高低进行。
- 进程回退法:让一(多)个进程回退到足以回避死锁的地步,进程回退时自愿释放资源而不是被剥夺。要求系统保持进程的历史信息,设置还原点。