臨界區(Critical Section)是一段供線程獨佔式訪問的代碼,也就是說若有一線程正在訪問該代碼段,其它線程想要訪問,只能等待當前線程離開該代碼段方可進入,這樣保證了線程安全。他工作於用戶級(相對於內核級),在Window系統中CRITICAL_SECTION實現臨界區相關機制。
二 臨界區相關函數:
void InitializeCriticalSection(LPCRITICAL_SECTION lpCriticalSection) // 初始化臨界區
void EnterCriticalSection(LPCRITICAL_SECTION lpCriticalSection) // 進入臨界區
void LeaveCriticalSection(LPCRITICAL_SECTION lpCriticalSection) // 離開臨界區
void DeleteCriticalSection(LPCRITICAL_SECTION lpCriticalSection) // 釋放臨界區資源
使用示例:
- #include <windows.h>
- static CRITICAL_SECTION cs; // 定義臨界區對象,如果程序是OOP的,可以定義爲類non-static成員
- // 在進入多線程環境之前,初始化臨界區
- InitializeCriticalSection(&cs);
- void f()
- {
- EnterCriticalSection(&cs);// 進入臨界區,其它線程則無法進入
- // 安全訪問該區域
- LeaveCriticalSection(&cs); // 離開臨界區,其它線程可以進入
- }
- // 釋放臨界區資源,當不再使用臨界區時調用該函數
- DeleteCriticalSection(&cs);
EnterCriticalSection和LeaveCriticalSection跟new/delete一樣是成對調用的,很多時候在調用EnterCriticalSection以後不得不在多處加入LeaveCriticalSection,因爲臨界區內有return,break,continue,goto等等跳轉,一不小心就會造成死鎖。基於這個原因,在很多開源代碼中都對CRITICAL_SECTION進行了封裝。下面是我從某開源庫中摘取的封裝後的代碼:
- #include <Windows.h>
- class Mutex {
- public:
- Mutex() { InitializeCriticalSection(§ion); }
- ~Mutex() { DeleteCriticalSection(§ion); }
- void Enter() { EnterCriticalSection(§ion); }
- void Leave() { LeaveCriticalSection(§ion); }
- struct Lock;
- protected:
- Mutex(const Mutex&);
- Mutex& operator=(const Mutex&);
- CRITICAL_SECTION section;
- };
- struct Mutex::Lock {
- Mutex& s;
- Lock(Mutex& s) : s(s) { s.Enter(); }
- ~Lock() { s.Leave(); }
- };
在進入臨界區的地方(函數體內)定義Mutex::Lock的對象作爲局部變量,通過Mutex::Lock對象的生命週期控制臨界區範圍。
使用示例:
- class A{
- public:
- void Foo();
- private:
- Mutex mutex;
- };
- void A::Foo()
- {
- Mutex::Lock lock(mutex);
- // 臨界區代碼
- }