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

Windows 多執行緒程式設計全攻略:Win32 API 與 MFC 兩大體系實戰詳解

     編輯:VC 教學

前言

執行緒是進程內的執行單元,擁有獨立堆疊、暫存器狀態,共享進程所有資源 (檔案控制代碼、記憶體、全域變數)。Windows 透過排程器將 CPU 時間片輪流分配給各執行緒,形成「同時運行」假象。本文系統梳理 **Win32 API** 與 **MFC** 兩大開發體系的建立、同步、終止全流程。

一、Win32 API 體系:最接近核心的控制權

1. 建立與終止執行緒


// 建立
HANDLE hThread = CreateThread(
    NULL,                // 安全性屬性
    0,                   // 堆疊大小 (0=預設 1MB)
    ThreadFunc,          // 進入點函式
    pParam,              // 傳遞參數
    0,                   // 建立旗標 (CREATE_SUSPENDED=暫緩啟動)
    &dwThreadId          // 接收執行緒 ID
);

// 進入點原型
DWORD WINAPI ThreadFunc(LPVOID pParam) { ... return 0; }

// 終止方式
// 內部正常返回 → 自動結束
ExitThread(dwExitCode);                    // 執行緒自我結束
TerminateThread(hThread, dwExitCode);      // **外部強制終止,極度不推薦** (資源洩漏、鎖死、堆疊損毀)

2. 執行緒同步四大核心物件

物件適用場景關鍵 API特點
Mutex (互斥體)跨進程/執行緒獨佔資源CreateMutex, WaitForSingleObject, ReleaseMutex核心物件、可命名跨進程、擁有權機制 (避免遺棄)
Semaphore (訊號)限制同時存取資源的執行緒數 (連線池、佇列槽位)CreateSemaphore, WaitForSingleObject, ReleaseSemaphore計數器模型、初始/最大計數可設定
Event (事件)執行緒間通知/等待條件 (資料就緒、關機訊號)CreateEvent, SetEvent, ResetEvent, WaitForSingleObject手動/自動重置、可命名跨進程
Critical Section (臨界區)**同進程內** 高效能互斥InitializeCriticalSection, Enter/TryEnter/LeaveCriticalSection**用戶模式**、無核心切換開銷、不可跨進程、支援自旋計數

3. 等待函式:同步的心跳


// 等單一物件
DWORD WaitForSingleObject(HANDLE h, DWORD dwMilliseconds); // INFINITE=永久等待

// 等多個物件
DWORD WaitForMultipleObjects(DWORD nCount, CONST HANDLE* lpHandles,
    BOOL bWaitAll, DWORD dwMilliseconds);
// bWaitAll=TRUE  全部觸發才返回;FALSE 任一觸發即返回

4. 經典範例:生產者-消費者 (Mutex + 兩個 Event)


HANDLE hMutex = CreateMutex(NULL, FALSE, NULL);
HANDLE hNotFull  = CreateEvent(NULL, FALSE, TRUE,  NULL);  // 初始有空槽
HANDLE hNotEmpty = CreateEvent(NULL, FALSE, FALSE, NULL);  // 初始無資料

// Producer
WaitForSingleObject(hNotFull, INFINITE);
WaitForSingleObject(hMutex, INFINITE);
// ... 寫入共享緩衝區 ...
ReleaseMutex(hMutex);
SetEvent(hNotEmpty);

// Consumer
WaitForSingleObject(hNotEmpty, INFINITE);
WaitForSingleObject(hMutex, INFINITE);
// ... 讀取共享緩衝區 ...
ReleaseMutex(hMutex);
SetEvent(hNotFull);

二、MFC 體系:封裝之美,生產力躍升

1. 兩種執行緒類型

  • 工作者執行緒:無訊息迴路,純計算/IO 任務,對應 AfxBeginThread(ThreadFunc, param)
  • 使用者介面執行緒:擁有訊息泵、視窗、可處理 UI,需衍生 CWinThread

2. 工作者執行緒建立與控制


UINT __cdecl MyThreadFunc(LPVOID pParam) {
    // pParam 可傳遞結構體指標
    for (int i=0; i<100; ++i) {
        if (::WaitForSingleObject(g_hStopEvent, 0) == WAIT_OBJECT_0) break;
        // 做工作...
        Sleep(50);
    }
    return 0;
}

// 啟動
CWinThread* pThread = AfxBeginThread(MyThreadFunc, pData,
    THREAD_PRIORITY_NORMAL, 0, 0, NULL);
// 掛起/恢復
pThread->SuspendThread(); pThread->ResumeThread();
// 等待結束
WaitForSingleObject(pThread->m_hThread, INFINITE);

3. UI 執行緒建立 (衍生 CWinThread)

  1. ClassWizard → Add Class → Base: CWinThread → 名稱 CMyUIThread
  2. 必須保留 DECLARE_DYNCREATE / IMPLEMENT_DYNCREATE
  3. 覆寫 InitInstance() (建立視窗) 與 ExitInstance() (清理)
  4. 啟動:AfxBeginThread(RUNTIME_CLASS(CMyUIThread)) 或兩階段 new CMyUIThread; pThread->CreateThread()

4. MFC 同步類別:RAII 風格,拒絕洩漏

Win32 物件MFC 封裝用法範例
MutexCMutexCMutex mut; CSingleLock lock(&mut); lock.Lock(); ... lock.Unlock();
SemaphoreCSemaphore同上,CSingleLock 通用
EventCEvent同上
CriticalSectionCCriticalSectionCCriticalSection cs; CSingleLock lock(&cs); lock.Lock(); ...
多物件等待:CMultiLock lock(arr, count); lock.Lock(INFINITE, FALSE); // 任一觸發

5. 範例:CCriticalSection 保護共享佇列


class CTaskQueue {
    std::queue q;
    CCriticalSection cs;
public:
    void Push(const Task& t) {
        CSingleLock lock(&cs); lock.Lock();
        q.push(t); lock.Unlock();
    }
    bool Pop(Task& t) {
        CSingleLock lock(&cs); lock.Lock();
        if (q.empty()) return false;
        t = q.front(); q.pop(); return true;
    }
};

三、進階主題與避坑指南

主題關鍵點
執行緒區域儲存 (TLS)TlsAlloc/SetValue/GetValue/Free;MFC: CWinThread::m_threadLocalData (內部使用)
執行緒優先權SetThreadPriority(h, THREAD_PRIORITY_HIGHEST/LOWEST/IDLE);動態調整避免飢餓
非同步 I/O (IOCP)CreateFile(FILE_FLAG_OVERLAPPED) + CreateIoCompletionPort,高併發網路/檔案伺服器標配
執行緒池Win32: QueueUserWorkItem / CreateThreadpoolWork (Vista+);避免頻繁建銷開銷
死鎖預防固定鎖順序、TryEnterCriticalSection 超時退避、避免持有鎖呼叫外部代碼
偽共享不同執行緒頻繁讀寫同一快取行的不同變數 → 显式對齊 alignas(64) 或分離熱點資料
除錯技巧Visual Studio: **執行緒視窗、平行堆疊、資料斷點、命名執行緒** (SetThreadDescription Win10+)

四、選型建議

  1. 純算力/IO、無 UI、追求極致效能/可移植 → **Win32 API + 標準 C++11/17 <thread> <mutex> <condition_variable>**
  2. MFC 專案、需與 UI 互動、快速開發 → **MFC AfxBeginThread + CSingleLock/CMultiLock**
  3. 新專案、跨平台、現代 C++ → **std::thread、std::jthread (C++20)、std::counting_semaphore、std::latch/barrier**

結語

多執行緒是把雙面刃:用得好是效能倍增器,用不好是 Bug 製造機。**核心原則只有三條**:(1) **最小化共享狀態** (傾向不可變資料、訊息傳遞);(2) **鎖的範圍最小、持有時間最短**;(3) **永遠在固定順序獲取多把鎖**。掌握 Win32 底層機制讓你心中有數,善用 MFC/STD 封裝讓你手中無碼、心中有碼。願你的執行緒永遠無競爭、無死鎖、無飢餓——只剩下優雅的並行。

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