核心概念速覽
- 進程:獨立虛擬位址空間、代碼、資料、資源;
- 執行緒:進程內獨立執行流,共享進程資源(全域變數、Handle),擁有私有堆疊、CPU 時間片;
- 分類:UI 執行緒(含訊息迴圈,如主執行緒)vs 工作執行緒(無訊息迴圈,後台計算/IO)。
執行緒建立與控制
工作執行緒(最常用)
// 1. 執行緒函數
UINT __cdecl WorkerThread(LPVOID pParam) {
CMyData* pData = (CMyData*)pParam;
while (!pData->bStop) {
// 執行任務...
Sleep(100);
}
return 0;
}
// 2. 啟動
CWinThread* pThread = AfxBeginThread(WorkerThread, pData, THREAD_PRIORITY_NORMAL);
UI 執行緒
// 需從 CWinThread 衍生,使用 DECLARE_DYNCREATE/IMPLEMENT_DYNCREATE
class CMyUIThread : public CWinThread {
DECLARE_DYNCREATE(CMyUIThread)
virtual BOOL InitInstance() { /* 建視窗 */ return TRUE; }
};
IMPLEMENT_DYNCREATE(CMyUIThread, CWinThread)
// 啟動
AfxBeginThread(RUNTIME_CLASS(CMyUIThread), THREAD_PRIORITY_NORMAL);
同步機制工具箱
| 機制 | 適用場景 | 關鍵 API |
| Critical Section | 進程內高頻短暫互斥 | CCriticalSection::Lock/Unlock |
| Mutex | 跨進程互斥 | CMutex, WaitForSingleObject |
| Event | 執行緒間信號通知 | CEvent::SetEvent/ResetEvent |
| Semaphore | 資源計數控制 | CSemaphore |
實戰案例:生產者-消費者數字排序
共享資料結構
struct SharedData {
CCriticalSection cs;
CEvent evDataReady;
CEvent evSpaceReady;
int buffer[100];
int head = 0, tail = 0, count = 0;
BOOL bStop = FALSE;
} g_Data;
生產者執行緒
UINT Producer(LPVOID) {
for (int i = 0; i < 1000 && !g_Data.bStop; ++i) {
g_Data.evSpaceReady.Lock(); // 等待空位
g_Data.cs.Lock();
g_Data.buffer[g_Data.tail] = rand() % 1000;
g_Data.tail = (g_Data.tail + 1) % 100;
g_Data.count++;
g_Data.cs.Unlock();
g_Data.evDataReady.SetEvent(); // 通知有數據
}
return 0;
}
消費者執行緒(排序輸出)
UINT Consumer(LPVOID) {
std::vector vec;
while (!g_Data.bStop || g_Data.count > 0) {
g_Data.evDataReady.Lock();
g_Data.cs.Lock();
if (g_Data.count > 0) {
vec.push_back(g_Data.buffer[g_Data.head]);
g_Data.head = (g_Data.head + 1) % 100;
g_Data.count--;
}
g_Data.cs.Unlock();
g_Data.evSpaceReady.SetEvent();
if (vec.size() >= 100) {
std::sort(vec.begin(), vec.end());
// 輸出或傳遞給 UI...
vec.clear();
}
}
return 0;
}
啟動與清理
CWinThread* pProd = AfxBeginThread(Producer, NULL);
CWinThread* pCons = AfxBeginThread(Consumer, NULL);
// 程式結束前
g_Data.bStop = TRUE;
g_Data.evDataReady.SetEvent();
g_Data.evSpaceReady.SetEvent();
WaitForSingleObject(pProd->m_hThread, INFINITE);
WaitForSingleObject(pCons->m_hThread, INFINITE);
優先級與調度
GetThreadPriority() / SetThreadPriority():相對優先級(同優先權層級內);
GetPriorityClass() / SetPriorityClass():進程優先權層級(跨層級);
- 高優先級搶佔低優先級,同級時間片輪轉。
執行緒終止三種方式
- 函數自然返回(推薦,配合旗標
bStop);
AfxEndThread() 內部自殺;
TerminateThread() 強制殺掉(危險:資源洩漏、鎖未釋放),慎用。
避坑指南
- UI 操作只能在 UI 執行緒(主執行緒)進行,工作執行緒需
PostMessage 轉發;
- 共享資料必須加鎖,
volatile 不能替代鎖;
- 避免巢狀鎖導致死鎖,固定鎖順序;
- 執行緒函數參數生命週期必須覆蓋執行緒存活期;
- MFC 物件跨執行緒傳遞需小心(
CWnd* 等不可直接跨執行緒用)。