zoukankan      html  css  js  c++  java
  • 多线程编程之线程死锁问题 转载

    在多线程编程中,除了要解决数据访问的同步与互斥之外,还需要解决的重要问题就是多线程的死锁问题。所谓死锁: 是指两个或两个以上的进程(线程)在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外部处理作用,它们都将无限等待下去。

    一、死锁原因与形成条件

      死锁形成的原因:

    1. 系统资源不足
    2. 进程(线程)推进的顺序不恰当;
    3. 资源分配不当

      死锁形成的条件:

    1. 互斥条件:所谓互斥就是进程在某一时间内独占资源。
    2. 请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。
    3. 不剥夺条件:进程已获得资源,在末使用完之前,不能强行剥夺。
    4. 循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。

      从编程经验上来讲,形成死锁的一般原因有以下几种:

    1. 个人使用锁的经验差异。
    2. 程序模块使用锁的差异。
    3. 工程代码版本之间的差异。
    4. 工程代码分支之间的差异。
    5. 修改代码和重构代码带来的差异。

    二、常见死锁形成的场景

      死锁形成的常见情况有以下几种:

    2.1 忘记释放锁

    复制代码
    void data_process()
    {
        EnterCriticalSection();
    
        if(/* error happens, forget LeaveCriticalSection */)
            return;
    
        LeaveCriticalSection();
    }
    复制代码

     2.2 单线程重复申请锁

    复制代码
    void sub_func()
    {
        EnterCriticalSection();
        do_something();
        LeaveCriticalSection();
    }
    
    void data_process()
    {
        EnterCriticalSection();
        sub_func();
        LeaveCriticalSection();
    }
    复制代码

     2.3 多线程多锁申请

    复制代码
    void data_process1()
    {
        EnterCriticalSection(&cs1);  // 申请锁的顺序有依赖
        EnterCriticalSection(&cs2);
        do_something1();
        LeaveCriticalSection(&cs2);
        LeaveCriticalSection(&cs1);
    }
    
    void data_process2()
    {
        EnterCriticalSection(&cs2);  // 申请锁的顺序有依赖
        EnterCriticalSection(&cs1);
        do_something2();
        LeaveCriticalSection(&cs1);
        LeaveCriticalSection(&cs2);
    }
    复制代码

     2.4 环形锁申请

    /* 多个线程申请锁的顺序形成相互依赖的环形:
    *             A   -  B
    *             |      |
    *             C   -  D
    */

     三、死锁的避免策略

      死锁的代价是非常大的,有时候很难检测排查,因此需要在编程过程中尽可能的避免发生死锁。编程中为了避免死锁应该遵循如下策略

    1. 在编写多线程程序之前,首先编写正确的程序,然后再移植到多线程。
    2. 时刻检查自己写的程序有没有在跳出时忘记释放锁。
    3. 如果自己的模块可能重复使用一个锁,建议使用嵌套锁
    4. 对于某些锁代码,不要临时重新编写,建议使用库里面的锁,或者自己曾经编写的锁。
    5. 如果某项业务需要获取多个锁,必须保证锁的按某种顺序获取,否则必定死锁。
    6. 编写简单的测试用例,验证有没有死锁。
    7. 编写验证死锁的程序,从源头避免死锁。

    四、死锁例子

    张三对李四说:“你给我画,我就把书给你。
    李四对张三说:“你给我书,我就把画给你
    class Zhangsan{    // 定义张三类
        public void say(){
            System.out.println("张三对李四说:“你给我画,我就把书给你。”") ;
        }
        public void get(){
            System.out.println("张三得到画了。") ;
        }
    };
    class Lisi{    // 定义李四类
        public void say(){
            System.out.println("李四对张三说:“你给我书,我就把画给你”") ;
        }
        public void get(){
            System.out.println("李四得到书了。") ;
        }
    };
    public class ThreadDeadLock implements Runnable{
        private static Zhangsan zs = new Zhangsan() ;        // 实例化static型对象
        private static Lisi ls = new Lisi() ;        // 实例化static型对象
        private boolean flag = false ;    // 声明标志位,判断那个先说话
        public void run(){    // 覆写run()方法
            if(flag){
                synchronized(zs){    // 同步张三
                    zs.say() ;
                    try{
                        Thread.sleep(500) ;
                    }catch(InterruptedException e){
                        e.printStackTrace() ;
                    }
                    synchronized(ls){
                        zs.get() ;
                    }
                }
            }else{
                synchronized(ls){
                    ls.say() ;
                    try{
                        Thread.sleep(500) ;
                    }catch(InterruptedException e){
                        e.printStackTrace() ;
                    }
                    synchronized(zs){
                        ls.get() ;
                    }
                }
            }
        }
        public static void main(String args[]){
            ThreadDeadLock t1 = new ThreadDeadLock() ;        // 控制张三
            ThreadDeadLock t2 = new ThreadDeadLock() ;        // 控制李四
            t1.flag = true ;
            t2.flag = false ;
            Thread thA = new Thread(t1) ;
            Thread thB = new Thread(t2) ;
            thA.start() ;
            thB.start() ;
        }
    };

    参考文献 http://www.cnblogs.com/kuliuheng/p/4071555.html

  • 相关阅读:
    bootstrap table 怎么自适应宽度
    nginx解决超长请求串(413 request Entity too Large错误解决办法)
    nginx proxy_buffer_size 解决后端服务传输数据过多,其实是header过大的问题
    测试了下boost的序列化反序列化功能
    测试C++代码与WebBrowser HTML的互动
    Open SSL 开发环境配置
    modern-cpp-features
    Qt程序调试之Q_ASSERT断言(条件为真则跳过,否则直接异常+崩溃)
    分布式事务
    Django admin
  • 原文地址:https://www.cnblogs.com/duange/p/6035237.html
Copyright © 2011-2022 走看看