多線程是現代 Windows 應用程式提升回應性、並行處理的關鍵技術。MFC 在 Win32 線程模型之上,提供了 CWinThread 類別與 AfxBeginThread 等全域函數,封裝了線程建立、同步、訊息迴路、例外處理等複雜細節。本文系統梳理 Win32 線程基礎、同步物件、MFC 線程類別體系與實戰開發模式。
線程優於進程的優勢:建立/切換速度快(無需重新映射映像)、共享記憶體簡化通訊。
MFC 未封裝進程管理,直接使用 Win32 API:
CreateProcess:建立新進程,參數涵蓋應用程式名、命令列、安全屬性、控制代碼繼承、建立旗標、環境塊、啟動資訊等。成功返回 PROCESS_INFORMATION(含進程/主線程句柄與 ID)。ExitProcess、主線程返回、最後一個線程結束、TerminateProcess(強制,不執行 DLL 入口點)。HANDLE CreateThread(
LPSECURITY_ATTRIBUTES lpThreadAttributes,
DWORD dwStackSize,
LPTHREAD_START_ROUTINE lpStartAddress,
LPVOID lpParameter,
DWORD dwCreationFlags, // CREATE_SUSPENDED 掛起建立
LPDWORD lpThreadId
);
SetPriorityClass/SetThreadPriority 調整。ExitThread、線程函數返回、TerminateThread、進程終止。注意:TerminateThread/Process 會跳過 DllMain,導致資源洩漏。Win32 TLS 機制:TlsAlloc 取得索引 → TlsSetValue 存指標 → TlsGetValue 取指標 → TlsFree 釋放。DLL 中典型用法:DllMain 中 DLL_PROCESS_ATTACH 分配索引、DLL_THREAD_ATTACH 為新線程配置記憶體並 TlsSetValue、DLL_THREAD_DETACH 釋放記憶體。
| 物件 | 適用範圍 | 關鍵 API |
|---|---|---|
| Critical Section | 同進程線程間 | InitializeCriticalSection, Enter/LeaveCriticalSection |
| Event | 跨進程 | CreateEvent, Set/Reset/PulseEvent(自動/手動重置) |
| Mutex | 跨進程 | CreateMutex, WaitForSingleObject, ReleaseMutex |
| Semaphore | 跨進程,資源計數 | CreateSemaphore, Wait/ReleaseSemaphore |
等待函數族群:WaitForSingleObject、WaitForMultipleObjects、MsgWaitForMultipleObjectsEx(支援訊息泵與 APC)、SignalObjectAndWait(原子性釋放並等待)。
CWinApp 即為典型 UI 線程。需從 CWinThread 衍生,覆寫 InitInstance(必須)、ExitInstance,使用 DECLARE_DYNCREATE/IMPLEMENT_DYNCREATE 支援動態建立。UINT AFX_CDECL ThreadProc(LPVOID pParam)。// UI 線程
CWinThread* AfxBeginThread(
CRuntimeClass* pThreadClass, int nPriority, UINT nStackSize,
DWORD dwCreateFlags, LPSECURITY_ATTRIBUTES lpSecurityAttrs);
// Worker 線程
CWinThread* AfxBeginThread(
AFX_THREADPROC pfnThreadProc, LPVOID pParam,
int nPriority, UINT nStackSize, DWORD dwCreateFlags,
LPSECURITY_ATTRIBUTES lpSecurityAttrs);
統一流程:建立 MFC 線程物件 → 呼叫 CWinThread::CreateThread → 內部呼叫 _beginthreadex 指定入口函數 _AfxThreadEntry → 同步事件 hEvent/hEvent2 協調父/子線程啟動順序(圖 8-1、8-2)。

作為 _beginthreadex 參數傳遞,包含父線程狀態指標、新線程物件指標、建立旗標、新處理器、同步事件、錯誤碼。子線程在 _AfxThreadEntry 中初始化自身線程狀態、繼承父線程模組狀態,隨後進入控制函數或 Run() 訊息迴路。
AfxEndThread:清理 MFC 物件、釋放 TLS 記憶體、呼叫 CWinThread::Delete(預設 delete this 並 CloseHandle)、呼叫 _endthreadex 釋放 CRT 資源(不關閉線程句柄)。m_bAutoDelete = TRUE(預設)自動銷毀 CWinThread 物件;若需線程結束後保留物件檢查結果,設為 FALSE 並手動刪除。核心邏輯:PumpMessage() 取得/轉譯/分派訊息 → 無訊息時呼叫 OnIdle(lIdleCount) 執行閒置處理(工具列更新等) → 收到 WM_QUIT 返回退出碼並呼叫 ExitInstance。
while (bDoingBackgroundProcessing) {
MSG msg;
while (::PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE)) {
if (!PumpMessage()) { bDoingBackgroundProcessing = FALSE; ::PostQuitMessage(0); break; }
}
LONG lIdle = 0;
while (AfxGetApp()->OnIdle(lIdle++)); // 執行 MFC 閒置處理
// 執行背景運算片段
}
同理,等待同步物件時可用 WaitForSingleObject(hEvent, 0) == WAIT_TIMEOUT 作為迴圈條件。
MFC 引入線程狀態、進程狀態、模組狀態等概念,支撐跨模組資源存取、句柄映射隔離等核心功能。詳細機制將於下一章(第 9 章)深入剖析。