什么是死锁?在并发程序设计中 , 死锁 (deadlock) 是一种十分常见的逻辑错误 。通过采用正确的编程方式 , 死锁的发生不难避免 。
死锁的四个必要条件
在计算机专业的本科教材中 , 通常都会介绍死锁的四个必要条件 。这四个条件缺一不可 , 或者说只要破坏了其中任何一个条件 , 死锁就不可能发生 。我们来复习一下 , 这四个条件是:
?互斥(Mutual exclusion):存在这样一种资源 , 它在某个时刻只能被分配给一个执行绪(也称为线程)使用;
?持有(Hold and wait):当请求的资源已被占用从而导致执行绪阻塞时 , 资源占用者不但无需释放该资源 , 而且还可以继续请求更多资源;
?不可剥夺(No preemption):执行绪获得到的互斥资源不可被强行剥夺 , 换句话说 , 只有资源占用者自己才能释放资源;
?环形等待(Circular wait):若干执行绪以不同的次序获取互斥资源 , 从而形成环形等待的局面 , 想象在由多个执行绪组成的环形链中 , 每个执行绪都在等待下一个执行绪释放它持有的资源 。
解除死锁的必要条件
不难看出 , 在死锁的四个必要条件中 , 第二、三和四项条件比较容易消除 。通过引入事务机制 , 往往可以消除第二、三两项条件 , 方法是将所有上锁操作均作为事务对待 , 一旦开始上锁 , 即确保全部操作均可回退 , 同时通过锁管理器检测死锁 , 并剥夺资源(回退事务) 。这种做法有时会造成较大开销 , 而且也需要对上锁模式进行较多改动 。
消除第四项条件是比较容易且代价较低的办法 。具体来说这种方法约定:上锁的顺序必须一致 。具体来说 , 我们人为地给锁指定一种类似“水位”的方向性属性 。无论已持有任何锁 , 该执行绪所有的上锁操作 , 必须按照一致的先后顺序从低到高(或从高到低)进行 , 且在一个系统中 , 只允许使用一种先后次序 。
请注意 , 放锁的顺序并不会导致死锁 。也就是说 , 尽管按照 锁A, 锁B, 放A, 放B 这样的顺序来进行锁操作看上去有些怪异 , 但是只要大家都按先A后B的顺序上锁 , 便不会导致死锁 。
举例
假如有三个对象A、B、C , 我们人为约定它们的锁序是: A 先于 B 先于 C 。举例说来 , 下列锁序均为合法:
?锁C , 放C
?锁B , 放B
?锁B , 锁C , 放B , 放C
?锁B , 锁C , 放C , 放B
?锁A , 放A
?锁A , 锁C , 放A , 放C
?锁A , 锁C , 放C , 放A
?锁A , 锁B , 放A , 放B
?锁A , 锁B , 放B , 放A
?锁A , 锁B , 锁C , 放A , 放B , 放C
?锁A , 锁B , 锁C , 放C , 放B , 放A
而在上面定义的系统中 , 可能导致发生死锁典型上锁序列包括:
?锁B , 锁A , 锁C , 放C , 放A , 放B
(因为先B后A的上锁顺序违反了锁序约定 , 如果另一执行绪同时按照先A后B的顺序上锁 , 则可能由于执行绪甲获得了B , 执行绪乙获得了A , 而导致双方同时等待对方释放所持有的锁 , 从而形成死锁局面;解法是将操作序列中增加适当的锁操作 , 即改为锁B , 放B , 锁A , 锁B , 锁C , 放C , 放A , 放B)
或者说 , 只要拿锁的时候不出现逆序(例如拿着C的时候试图抓B或A , 或者拿着B的时候试图抓A) , 并出现潜在逆序的时候先放掉“小”锁再抓大的 , 就一定不造成死锁了 。
什么是死锁(deadlock)?所谓死锁: 是指两个或两个以上的进程在执行过程中 , 因争夺资源而造成的一种互相等待的现象 , 若无外力作用 , 它们都将无法推进下去 。此时称系统处于死锁状态或系统产生了死锁 , 这些永远在互相等待的进程称为死锁进程 。
由于资源占用是互斥的 , 当某个进程提出申请资源后 , 使得有关进程在无外力协助下 , 永远分配不到必需的资源而无法继续运行 , 这就产生了一种特殊现象死锁 。一种情形 , 此时执行程序中两个或多个线程发生永久堵塞(等待) , 每个线程都在等待被其他线程占用并堵塞了的资源 。例如 , 如果线程A锁住了记录1并等待记录2 , 而线程B锁住了记录2并等待记录1 , 这样两个线程就发生了死锁现象 。计算机系统中,如果系统的资源分配策略不当 , 更常见的可能是程序员写的程序有错误等 , 则会导致进程因竞争资源不当而产生死锁的现象 。
秒懂生活扩展阅读
- 转继承的特征怎样规定的
- 唯美好听的句子
- 红茶如何制作方法
- 正宗毛氏回锅肉是怎么做的
- 工业分析技术专业的就业前景怎么样
- 桑德尔公开课 桑德尔
- 南方端午节门口挂的什么植物
- 属猴男和属马女的婚姻配吗
- 增香的大料有哪些
- 网王小说女主是超可爱的天然呆