多執行緒並發存取共享資料時,會發生競態條件。例如執行緒 1 讀取結構體 s.a、s.b 時,執行緒 2 修改它們,導致讀到不一致的「混合狀態」。解決之道是互斥鎖:存取前必須取得鎖,用完釋放,同一時間僅一執行緒持有。
| 物件 | 屬性 | 適用場景 |
|---|---|---|
| Mutex、Semaphore、Event | 核心物件,需用戶/核心模式切換 | 跨進程同步、複雜等待邏輯 |
| Critical Section | 用戶模式,無模式切換開銷 | 單進程內高頻率互斥 (首選) |
Critical Section 效能最佳,但僅限單進程內使用。
CRITICAL_SECTION cs;
InitializeCriticalSection(&cs);
// 執行緒 1
EnterCriticalSection(&cs); int a=s.a, b=s.b; LeaveCriticalSection(&cs);
// 執行緒 2
EnterCriticalSection(&cs); s.a++; s.b--; LeaveCriticalSection(&cs);
DeleteCriticalSection(&cs);
缺點:鎖變數 cs 與受保護資料 s 僅邏輯關聯,易忘鎖、漏解鎖、异常時洩漏。
class InstanceLockBase {
CRITICAL_SECTION cs;
friend class InstanceLock; // 允許鎖類別存取私有鎖操作
void Lock() { EnterCriticalSection(&cs); }
void Unlock() { LeaveCriticalSection(&cs); }
protected:
InstanceLockBase() { InitializeCriticalSection(&cs); }
~InstanceLockBase() { DeleteCriticalSection(&cs); }
};
struct MyData : public InstanceLockBase { ... };
class InstanceLock {
InstanceLockBase* _pObj;
public:
explicit InstanceLock(InstanceLockBase* pObj) : _pObj(pObj) {
if (_pObj) _pObj->Lock(); // 建構時加鎖
}
~InstanceLock() {
if (_pObj) _pObj->Unlock(); // 離開作用域自動解鎖
}
};
MyData data; // 含鎖的資料
void ModifyData() {
InstanceLock lock(&data); // 函數進入加鎖
// 對 data 任意操作...
} // 函數結束 lock 解構 → 自動解鎖
void PartialLock() {
// ... 其他代碼
{
InstanceLock lock(&data); // 僅此區塊加鎖
// 關鍵區段操作
} // 離開區塊自動解鎖
// ... 其他代碼
}
主執行緒持有鎖 3 秒,子執行緒嘗試取得鎖:
// 輸出時間戳記
001 [13:43:23.781] in main thread, lock
002 [13:43:26.781] in main thread, unlock
003 [13:43:26.781] in sub thread, lock // 主釋放後子才取得
004 [13:43:28.781] in sub thread, unlock
清晰展示互斥運作正常。
#pragma once
#include
class InstanceLock; // 前向宣告
class InstanceLockBase {
friend class InstanceLock;
CRITICAL_SECTION cs;
void Lock() { ::EnterCriticalSection(&cs); }
void Unlock() { ::LeaveCriticalSection(&cs); }
protected:
InstanceLockBase() { ::InitializeCriticalSection(&cs); }
~InstanceLockBase() { ::DeleteCriticalSection(&cs); }
};
class InstanceLock {
InstanceLockBase* _pObj;
public:
explicit InstanceLock(InstanceLockBase* pObj) : _pObj(pObj) {
if (_pObj) _pObj->Lock();
}
~InstanceLock() {
if (_pObj) _pObj->Unlock();
}
};
下一篇將實作讀寫鎖 (Reader-Writer Lock),允許多讀者並發、讀寫/寫寫互斥,基於 Mutex 與 WaitForMultipleObjects 實現,並示範模板技巧簡化介面。