zoukankan      html  css  js  c++  java
  • 【C++多线程】嵌套锁/递归锁std::recursive_mutex和Windows临界区

    Windows临界区

      Windows临界区,同一个线程是可以重复进入的,但是进入的次数与离开的次数必须相等C++互斥量则不允许同一个线程重复加锁。windows临界区是在windows编程中的内容,了解一下即可,效果几乎可以等同于c++11的mutex。包含#include <windows.h>。windows中的临界区同mutex一样,可以保护一个代码段。但windows的临界区可以进入多次,离开多次,但是进入的次数与离开的次数必须相等,不会引起程序报异常出错。

      CRITICAL_SECTION对应std::mutex, EnterCriticalSection()对应lock(),LeaveCriticalSection()对应unlock()。

      1 #include <iostream>
      2 #include <thread>
      3 #include <list>
      4 #include <mutex>
      5 #include <Windows.h>
      6 
      7 #define __WINDOWSJQ_
      8 
      9 using namespace std;
     10 
     11 class A
     12 {
     13 public:
     14     // 把收到的消息传入队列
     15     void inMsgRecvQueue()
     16     {
     17         for (size_t i = 0; i < 1000; ++i)
     18         {
     19             cout << "收到消息,并放入队列 " << i << endl;
     20 
     21 #ifdef  __WINDOWSJQ_
     22             EnterCriticalSection(&my_winsec);    //    进入临界区
     23             //EnterCriticalSection(&my_winsec);    //    可以再次进入临界区,程序不会出错
     24             msgRecvQueue.push_back(i);
     25             LeaveCriticalSection(&my_winsec);    //    离开临界区
     26             //LeaveCriticalSection(&my_winsec);    //    如果进入两次,必须离开两次不会报错
     27 #elif
     28             my_mutex.lock();
     29             msgRecvQueue.push_back(i);
     30             my_mutex.unlock();
     31 #endif //  __WINDOWSJQ_
     32         }
     33 
     34         cout << "消息入队结束" << endl;
     35     }
     36 
     37     // 从队列中取出消息
     38     void outMsgRecvQueue()
     39     {
     40         for (size_t i = 0; i < 1000; ++i)
     41         {
     42 #ifdef  __WINDOWSJQ_
     43             EnterCriticalSection(&my_winsec);    //    进入临界区
     44             if (!msgRecvQueue.empty())
     45             {
     46                 // 队列不为空
     47                 int num = msgRecvQueue.front();
     48                 cout << "从消息队列中取出 " << num << endl;
     49                 msgRecvQueue.pop_front();
     50             }
     51             else
     52             {
     53                 // 消息队列为空
     54                 cout << "消息队列为空 " << endl;
     55             }
     56             LeaveCriticalSection(&my_winsec);    //    离开临界区
     57 #elif
     58             my_mutex.lock();
     59             if (!msgRecvQueue.empty())
     60             {
     61                 // 队列不为空
     62                 int num = msgRecvQueue.front();
     63                 cout << "从消息队列中取出 " << num << endl;
     64                 msgRecvQueue.pop_front();
     65                 my_mutex.unlock();
     66             }
     67             else
     68             {
     69                 // 消息队列为空
     70                 cout << "消息队列为空 " << endl;
     71                 my_mutex.unlock();
     72             }
     73 #endif //  __WINDOWSJQ_
     74         }
     75 
     76         cout << "消息出队结束" << endl;
     77     }
     78 
     79     A()
     80     {
     81 #ifdef __WINDOWSJQ_
     82         InitializeCriticalSection(&my_winsec);    //    用临界区之前要初始化
     83 #endif // __WINDOWSJQ_
     84 
     85     }
     86 
     87 private:
     88     list<int> msgRecvQueue;
     89     mutex my_mutex;
     90 
     91 #ifdef __WINDOWSJQ_
     92     CRITICAL_SECTION my_winsec;    //    windows中的临界区,非常类似C++11中的mutex
     93 #endif // __WINDOWSJQ_
     94 
     95 };
     96 
     97 int main()
     98 {
     99     A myobj;
    100     thread    myInMsgObj(&A::inMsgRecvQueue, &myobj);
    101     thread    myOutMsgObj(&A::outMsgRecvQueue, &myobj);
    102     myInMsgObj.join();
    103     myOutMsgObj.join();
    104 
    105     getchar();
    106     return 0;
    107 }

      使用RAII实现windows版的lock_guard<>

     1 class CWinLock {
     2 public:
     3     CWinLock(CRITICAL_SECTION *pCritmp)
     4     {
     5         my_winsec =pCritmp;
     6         EnterCriticalSection(my_winsec);
     7     }
     8     ~CWinLock()
     9     {
    10         LeaveCriticalSection(my_winsec)
    11     };
    12 private:
    13     CRITICAL_SECTION *my_winsec;
    14 };

    std::recursive_mutex嵌套锁/递归锁

      std::recursive_mutex 与 std::mutex 一样,也是一种可以被上锁的对象,但是和 std::mutex 不同的是,std::recursive_mutex 允许同一个线程对互斥量多次上锁(即递归上锁),来获得对互斥量对象的多层所有权,std::recursive_mutex 释放互斥量时需要调用与该锁层次深度相同次数的 unlock(),可理解为 lock() 次数和 unlock() 次数相同,除此之外,std::recursive_mutex 的特性和 std::mutex 大致相同。

      例如函数a需要获取锁mutex,函数b也需要获取锁mutex,同时函数a中还会调用函数b。如果使用std::mutex必然会造成死锁。但是使用std::recursive_mutex就可以解决这个问题。

    参考

    https://blog.csdn.net/qq_38231713/article/details/106093490

  • 相关阅读:
    基于s5pv210的uboot总结
    QQ群笔记
    设计模式----适配器模式
    设计模式----桥接模式
    设计模式----建造者模式
    设计模式----原型模式
    设计模式----单例模式
    设计模式----工厂方法模式
    设计模式----设计原则
    JUnit单元测试--小试牛刀
  • 原文地址:https://www.cnblogs.com/chen-cs/p/13066083.html
Copyright © 2011-2022 走看看