【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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM