首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> C++ >> 關於C++

Win32 多執行緒同步實戰 (上):以 Critical Section 封裝 RAII 鎖類別

     編輯:關於C++

背景:為什麼需要鎖?

多執行緒並發存取共享資料時,會發生競態條件。例如執行緒 1 讀取結構體 s.a、s.b 時,執行緒 2 修改它們,導致讀到不一致的「混合狀態」。解決之道是互斥鎖:存取前必須取得鎖,用完釋放,同一時間僅一執行緒持有。

Win32 同步物件選擇

物件屬性適用場景
Mutex、Semaphore、Event核心物件,需用戶/核心模式切換跨進程同步、複雜等待邏輯
Critical Section用戶模式,無模式切換開銷單進程內高頻率互斥 (首選)

Critical Section 效能最佳,但僅限單進程內使用。

從手動管理到 RAII 封裝

原始 API 用法


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 僅邏輯關聯,易忘鎖、漏解鎖、异常時洩漏。

步驟 1:InstanceLockBase — 將鎖內嵌於資料類別


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 { ... };
  • 鎖成為資料物件不可分割的一部分 (組合關係)。
  • 建構/解構自動初始化/銷毀 Critical Section。

步驟 2:InstanceLock — RAII 鎖衛士


class InstanceLock {
    InstanceLockBase* _pObj;
public:
    explicit InstanceLock(InstanceLockBase* pObj) : _pObj(pObj) {
        if (_pObj) _pObj->Lock(); // 建構時加鎖
    }
    ~InstanceLock() {
        if (_pObj) _pObj->Unlock(); // 離開作用域自動解鎖
    }
};
  • 利用 C++ 建構/解構配對保證,確保鎖成對操作。
  • 區塊結束自動解鎖,異常安全。

使用範例


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 實現,並示範模板技巧簡化介面。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved