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

MFC 線程同步:深入掌握臨界區的應用與實作

     編輯:關於VC++

在多線程程式設計中,資料競爭是最常見也最棘手的問題。當多個線程同時存取共享資料時,若缺乏適當的同步機制,極易導致資料損毀或程式行為不可預期。臨界區是 Windows 提供的一種輕量級同步物件,專門用於保護單一進程內多線程對共享資源的獨佔存取。本文將詳細介紹 MFC 中 CCriticalSection 類的使用方法,並透過完整的程式碼範例示範如何建立線程安全的資料結構。

臨界區的核心概念

臨界區物件確保同一時間只有一個線程能進入受保護的程式碼區段。當線程嘗試進入已被佔用的臨界區時,會自動進入等待狀態,直到擁有權的線程釋放為止。與互斥量不同,臨界區無法跨進程使用,但效能更高、開銷更小,是單一進程內線程同步的首選方案。

MFC 中的 CCriticalSection 類

MFC 透過 CCriticalSection 類封裝了 Windows 臨界區 API。使用前需在標頭檔包含 afxmt.h。基本操作只有兩個核心方法:

  • Lock():請求擁有權,若已被佔用則阻塞等待
  • Unlock():釋放擁有權,喚醒等待中的線程

實作線程安全的資料陣列類別

以下範例展示如何將臨界區封裝於資料類別內部,對外提供線程安全的介面:

class CDataArray
{
private:
    int iArray[10];
    CCriticalSection CriticalSection;  // 內建同步物件

public:
    CDataArray() {}
    ~CDataArray() {}
    
    void SetData(int iValue);
    void GetDataArray(int aArray[10]);
};

// 寫入操作 - 完整鎖定保護
void CDataArray::SetData(int iValue)
{
    CriticalSection.Lock();
    for (int i = 0; i < 10; i++)
        iArray[i] = iValue;
    CriticalSection.Unlock();
}

// 讀取操作 - 同樣需要鎖定保護
void CDataArray::GetDataArray(int aArray[10])
{
    CriticalSection.Lock();
    for (int i = 0; i < 10; i++)
        aArray[i] = iArray[i];
    CriticalSection.Unlock();
}

多線程讀寫測試範例

建立全域資料實例,並啟動兩個工作者線程分別進行寫入與讀取:

CDataArray DataArray;  // 共享資料實例

// 寫入線程:循環寫入 0-9,每次間隔 500ms
UINT Thread_WriteProc(LPVOID param)
{
    for (int i = 0; i < 10; i++)
    {
        DataArray.SetData(i);
        ::Sleep(500);
    }
    return 0;
}

// 讀取線程:循環讀取 20 次並顯示訊息框
UINT Thread_ReadProc(LPVOID param)
{
    int aArray[10];
    for (int i = 0; i < 20; i++)
    {
        DataArray.GetDataArray(aArray);
        char str[255] = {0};
        for (int j = 0; j < 10; j++)
        {
            int len = strlen(str);
            wsprintf(&str[len], "%d", aArray[j]);
        }
        ::MessageBox((HWND)param, str, "Thread Read Proc", MB_OK);
    }
    return 0;
}

// 啟動線程
HWND hWnd = GetSafeHwnd();
AfxBeginThread(Thread_WriteProc, hWnd);
AfxBeginThread(Thread_ReadProc, hWnd);

關鍵注意事項

  1. 鎖定範圍最小化:僅在存取共享資料的程式碼區段加鎖,避免在鎖定狀態下執行耗時操作(如 I/O、Sleep、MessageBox)
  2. 確保成對呼叫:每個 Lock() 必須對應一個 Unlock(),建議使用 RAII 包裝類(如 CSingleLock)防止因異常導致死鎖
  3. 避免巢狀鎖定:同一線程重複呼叫 Lock() 會導致死鎖,臨界區不支援遞迴鎖定

總結

臨界區是 MFC 多線程程式設計中最基礎也最重要的同步工具。透過將 CCriticalSection 封裝於資料類別內部,可有效隔離同步邏輯,降低使用者誤用風險。實務上建議搭配 CSingleLock 使用,確保異常安全與程式碼可維護性。

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