【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

posted @ 2020-07-06 13:43  Chen沉尘  阅读(4046)  评论(0编辑  收藏  举报