• c++ 防范死锁的多种方法


    c++ 防范死锁

    • 死锁:多线程并发程序中,线程之间相互等待不可抢占的资源,从而造成死锁。

    死锁案例

    • 两个线程互相等待互斥锁。从而导致死锁。

      #include 
      #include 
      #include 
      
      std::mutex m1;
      std::mutex m2;
      
      void f(void)
      {
          std::lock_guard k(m1);
          printf("get lock 1\n");
          std::lock_guard k1(m2);
          printf("get lock 2\n");
      }
      
      void f1(void)
      {
          std::lock_guard k(m2);
          printf("get lock 2\n");
          std::lock_guard k1(m1);
          printf("get lock 1\n");
      }
      
      int main()
      {
          std::thread t(f);
          std::thread t1(f1);
      
          t.join();
          t1.join();
          printf("main exit\n");
          return 0;
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27
      • 28
      • 29
      • 30
      • 31
      • 32
      • 33

    解决方法

    • 使用相同的顺序获取锁。不小心即会犯错。

    • 使用 std::lock 同时获取多把锁。std::lock 可以同时锁住多个互斥,但不会自动解锁,需要配合 std::lock_guard 或者 std::unique_lock 使用,使其能够自动解锁。

    • 使用 std::scoped_lock 同时获取多把锁。std::scoped_lock 与 std::lock_guard 完全等价,只不过前者是可变函数模板,可以接收多个互斥。

      #include 
      #include 
      #include 
      
      std::mutex m1;
      std::mutex m2;
      static int method = 3;
      // 需要 c++17
      
      void f(void)
      {
          // 方法 1,按照相同的顺序获取锁
          if (0 == method) {
              std::lock_guard k(m1);
              printf("thread 1 get lock 1\n");
              std::lock_guard k1(m2);
              printf("thread 1 get lock 2\n");
          }
      
          // 方法 2,std::lock 与 std::lock_guard 配合使用
          if (1 == method) {
              // 锁住 m1 和 m2
              std::lock(m1, m2);
              printf("thread 1 get lock 1 and 2\n");
              // std::adopt_lock 指明互斥已被锁住
              std::lock_guard k(m1, std::adopt_lock);
              std::lock_guard k1(m2, std::adopt_lock);
          }
      
          // 方法 3,std::lock 与 std::unique_lock  配合使用
          if (2 == method) {
              // std::defer_lock 指明不需要对互斥进行加锁
              std::unique_lock k(m1, std::defer_lock);
              std::unique_lock k1(m2, std::defer_lock);
              // 锁住 k 和 k1
              std::lock(k, k1);
              printf("thread 1 get lock 1 and 2\n");
          }
      
          // 方法 4,使用 std::scoped_lock
          if (3 == method) {
              std::scoped_lock k(m1, m2);
              printf("thread 1 get lock 1 and 2\n");
          }
      }
      
      void f1(void)
      {
          if (0 == method) {
              std::lock_guard k(m1);
              printf("thread 2 get lock 1\n");
              std::lock_guard k1(m2);
              printf("thread 2 get lock 2\n");
          }
      
          if (1 == method) {
              std::lock(m1, m2);
              printf("thread 2 get lock 1 and 2\n");
              std::lock_guard k(m1, std::adopt_lock);
              std::lock_guard k1(m2, std::adopt_lock);
          }
      
          if (2 == method) {
              std::unique_lock k(m1, std::defer_lock);
              std::unique_lock k1(m2, std::defer_lock);
              std::lock(k, k1);
              printf("thread 2 get lock 1 and 2\n");
          }
      
          if (3 == method) {
              std::scoped_lock k(m1, m2);
              printf("thread 2 get lock 1 and 2\n");
          }
      }
      
      int main()
      {
          std::thread t(f);
          std::thread t1(f1);
      
          t.join();
          t1.join();
          printf("main exit\n");
          return 0;
      }
      
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27
      • 28
      • 29
      • 30
      • 31
      • 32
      • 33
      • 34
      • 35
      • 36
      • 37
      • 38
      • 39
      • 40
      • 41
      • 42
      • 43
      • 44
      • 45
      • 46
      • 47
      • 48
      • 49
      • 50
      • 51
      • 52
      • 53
      • 54
      • 55
      • 56
      • 57
      • 58
      • 59
      • 60
      • 61
      • 62
      • 63
      • 64
      • 65
      • 66
      • 67
      • 68
      • 69
      • 70
      • 71
      • 72
      • 73
      • 74
      • 75
      • 76
      • 77
      • 78
      • 79
      • 80
      • 81
      • 82
      • 83
      • 84
      • 85
      • 86

    如何预防死锁

    • 避免使用嵌套锁,若真的需要嵌套锁,应使用 std::scoped_lock;
    • 依从固定顺序获取锁。
  • 相关阅读:
    Detecting Deepfakes with Self-Blended Images翻译
    Java面试题-Java核心基础-第五天(面向对象基础)
    测试开发基础 | Python 算法与数据结构面试题系列一(附答案)
    Linux的初步认识和环境搭建
    一文搞懂 == 、equals和hashCode
    数字孪生可视化平台多少钱?费用有哪些首选广州华锐互动
    MySQL之视图、存储过程
    业务:财会业务知识之借贷记账法
    全同态加密:GSW
    FPGA ZYNQ VIVADO创建IP核点亮LED灯 方式一
  • 原文地址:https://blog.csdn.net/luohaha66/article/details/134272048