當多線程同步需求跨越進程邊界時,臨界區便無法滿足需求。互斥量是 Windows 提供的核心同步物件,不僅支援單一進程內線程同步,更能實現跨進程的資源共享保護。本文深入解析 MFC CMutex 類的使用機制,並對比臨界區的異同,幫助開發者選擇適合的同步策略。
| 特性 | 臨界區 | 互斥量 |
|---|---|---|
| 跨進程同步 | 不支援 | 支援(命名互斥量) |
| 效能開銷 | 極低(用戶模式) | 較高(核心模式轉換) |
| 等待機制 | 自旋鎖 + 核心事件 | 核心調度器管理 |
| 擁有權檢查 | 無 | 支援(僅擁有者可釋放) |
| 遺棄處理 | 無 | WAIT_ABANDONED 通知 |
MFC 要求使用 CSingleLock 或 CMultiLock 來管理互斥量的鎖定/釋放,這是 RAII 模式的體現:
#include "afxmt.h"
class CDataArray
{
private:
int iArray[10];
CMutex Mutex; // 互斥量物件
public:
CDataArray() {}
~CDataArray() {}
void SetData(int iValue);
void GetDataArray(int aArray[10]);
};
// 使用 CSingleLock 實現自動鎖定/釋放
void CDataArray::SetData(int iValue)
{
CSingleLock SingleLock(&Mutex); // 建構時自動嘗試鎖定
SingleLock.Lock(); // 明確鎖定(建構函數預設不鎖定)
for (int i = 0; i < 10; i++)
iArray[i] = iValue;
// 解構時自動呼叫 Unlock(),確保異常安全
}
void CDataArray::GetDataArray(int aArray[10])
{
CSingleLock SingleLock(&Mutex);
SingleLock.Lock();
for (int i = 0; i < 10; i++)
aArray[i] = iArray[i];
}
實現跨進程同步需在建構互斥量時指定名稱:
// 建立命名互斥量,第二個參數為初始擁有權,第三個為名稱
CMutex Mutex(FALSE, "Global\\MySharedMutex");
// 其他進程使用相同名稱開啟既有互斥量
CMutex Mutex(FALSE, "Global\\MySharedMutex");
注意:命名互斥量名稱建議加上 "Global\\" 前綴以確保跨會話可見性,且需處理 ERROR_ALREADY_EXISTS 以區分建立者與開啟者。
若擁有互斥量的線程意外終止未釋放,下一個等待線程將獲得 WAIT_ABANDONED 狀態碼,可藉此偵測並修復可能受損的共享資料:
CSingleLock lock(&Mutex);
DWORD result = lock.Lock(INFINITE);
if (result == WAIT_ABANDONED)
{
// 前一擁有者異常終止,共享資料可能處於不一致狀態
// 執行資料驗證與修復邏輯
RepairSharedData();
}
Lock(timeout) 並處理逾時情況WAIT_ABANDONED互斥量是解決跨進程同步問題的標準方案。MFC 的 CMutex 搭配 CSingleLock 提供了型別安全、異常安全的介面。開發者應根據同步範圍(進程內 vs 跨進程)、效能需求、容錯要求,在臨界區與互斥量之間做出明智選擇。