Linux下死锁的必要条件及预防方法


在linux下产生死锁有四个必要条件

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

(2) 请求与保持条件:一个进程(线程)因请求资源而阻塞时,对已获得的资源保持不放。
(3) 不剥夺条件 : 此进程(线程)已获得的资源,在末使用完之前,不能强行剥夺。
(4) 循环等待条件 : 多个进程(线程)之间形成一种头尾相接的循环等待资源关系。

避免死锁的方法:

在用户态,由于Linux提倡进程之间的公平,线程之间甚至没有优先级之分,每个进程/线程都会有机会执行,所以不会出现那种高优先级进程/线程抢占低优先级之后,由于低优先级进程/线程的等待导致的死锁,所以用户态还不需要关心这样的问题。

用户态遇到的死锁主要是循环等待,退几步来说,可能就是在临界区sleep的死锁了,查这种死锁很简单,为锁添加计数值就可以。

此外,之前提到pthread_mutex_t是具有优先级的,一个优先级比锁的优先级高的线程无法对其加锁,这防止了高优先级线程抢占低优先级线程的资源而导致饥饿,优先级导致的饥饿问题到内核态就变得非常麻烦。

还有一个就是自死锁,重复对互斥量加锁两次,线程自己等待自己,还是属于循环等待类型的。

在内核态,死锁问题除了在用户态的那些问题,最麻烦的就是存在不同的优先级与并发。

首先要明确,内核态的并发有以下几个因素:

1.中断并发,任何时候都可能发生,也是内核抢占的基础之一,通过关中断来禁止并发

2.多处理器并发,具备多个处理器核心时会发生,是真正的并发,通过加锁来禁止并发

3.内核抢占并发,在支持内核抢占时会发生,属于轮换并发,通过设置标识来禁止并发

4.调度并发,在进程上下文的切换时发生,内核共享处理器时间的基础,不能禁止,但内核保证所有进程/线程都将得到执行,这跟用户态的问题一致

中断在系统中优先级最高,任何一个时间点上都可能发生,由于时序需要,它所执行的代码都必须极度简单,通过用户态那样的优先级策略来使加锁失败显然不好,中断上下文所面临的主要问题有3个,第一是SMP系统的处理器并发,此时必须对共享数据加锁;第二是它所打断的代码的并发,如果打断的代码已经加锁,此时必是死锁无疑,故而所有内核代码,只要跟中断处理程序共享锁,必须先关中断,防止死锁;第三是中断处理程序之间的并发,中断可以打断另外一个中断,如果中断处理程序之间共享锁,这如果发生在同一个处理器上是会死锁的,发生在不同处理器上则不会。总而言之,只要跟中断处理程序共享的任何锁都要关中断,中断的死锁主要就是抢占引起的。

处理器并发的主要问题是为了优化效率,采用了一些处理器私有的数据,不必要加锁,对这些数据的访问必须禁止内核抢占,但不必要禁止中断。禁止抢占的问题在于抢占的代码会重新调度处理器,会访问到错误的数据,这当然不是本文重点,重点是死锁,多枚处理器如果出现互相抢占资源导致的循环等待简直就是奇观,CPU的核心之间相互循环等待,这有点太坑了。CPU并发使用多个资源应该按照一致的顺序持有,出于优雅美观的需求,按顺序释放也是非常必要的。处理器的死锁主要是循环等待引起的。

从内核抢占的名字可以看出来,它的死锁问题也主要是抢占引起的,但它不像中断那样优越,它必须满足一堆的条件才能抢占,所以规避了很多的问题,实际需要注意的主要就剩下调度所产生的轮换并发了,这里有一篇不错的博文可以看看,论述了内核抢占的机制。

调度并发实际上就是轮换使用处理器的结果,这导致任务的碎片化,它是进程抽象的基础,它的代码按逻辑执行,但任何一点都可能被抢占,所以它需要注意的就是,注意不要去惹中断和处理器的私有数据,不得已要去弄一下了,记得关中断,加锁,禁止抢占啥的就OK了。

原博客:http://www.cnblogs.com/huyc/archive/2012/12/18/2823647.html




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值