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就可以解決這個問題。