Win32 API 提供了豐富的線程管理機制。本文基於《Windows程序設計》學習筆記,系統梳理線程核心概念、關鍵API(CreateThread/WaitForSingleObject/WaitForMultipleObjects/SetThreadPriority/ExitThread/TerminateThread)、內核對象結構、上下文切換、優先級體系、終止方式及最佳實踐,附帶完整可編譯示例代碼。
| 概念 | 說明 |
|---|---|
| 線程 | 進程內代碼執行路徑,擁有獨立棧、寄存器上下文、線程局部存儲(TLS) |
| _stdcall | Win32回調函數調用約定:參數右至左入棧,被調用者清棧(callee cleanup) |
| 線程內核對象 | 內核維護的數據結構,包含:上下文、使用計數、暫停計數、退出碼、信號狀態等 |
| 受信/非受信 | 線程運行中=非受信;線程結束=受信。Wait函數等待對象變為受信 |
| 使用計數 | 創建時=2(內核引用+句柄引用),CloseHandle遞減,歸零時對象銷毀 |
| 暫停計數 | CREATE_SUSPENDED創建時=1,ResumeThread遞減,歸零時獲得CPU調度 |
HANDLE CreateThread(
LPSECURITY_ATTRIBUTES lpThreadAttributes, // 安全屬性,NULL=默認
SIZE_T dwStackSize, // 棧大小,0=默認1MB
LPTHREAD_START_ROUTINE lpStartAddress, // 線程入口函數
LPVOID lpParameter, // 傳給入口函數的參數
DWORD dwCreationFlags, // 0=立即運行, CREATE_SUSPENDED=掛起
LPDWORD lpThreadId // 輸出:線程ID
);
DWORD WaitForSingleObject(HANDLE hHandle, DWORD dwMilliseconds); // dwMilliseconds: INFINITE=無限等待, 0=嘗試, >0=超時毫秒數 // 返回: WAIT_OBJECT_0(受信), WAIT_TIMEOUT(超時), WAIT_FAILED(失敗)
DWORD WaitForMultipleObjects(
DWORD nCount, // 對象數量(最大 MAXIMUM_WAIT_OBJECTS=64)
CONST HANDLE* lpHandles, // 句柄數組
BOOL bWaitAll, // TRUE=全部受信, FALSE=任一受信
DWORD dwMilliseconds // 超時
);
// 返回: WAIT_OBJECT_0 + index (bWaitAll=FALSE時), WAIT_OBJECT_0 (bWaitAll=TRUE時)
BOOL SetThreadPriority(HANDLE hThread, int nPriority); // 相對優先級常量(從高到低): // THREAD_PRIORITY_TIME_CRITICAL (15) // THREAD_PRIORITY_HIGHEST (2) // THREAD_PRIORITY_ABOVE_NORMAL (1) // THREAD_PRIORITY_NORMAL (0) ← 默認 // THREAD_PRIORITY_BELOW_NORMAL (-1) // THREAD_PRIORITY_LOWEST (-2) // THREAD_PRIORITY_IDLE (-15) // 進程優先級類別(影響線程基礎優先級): // IDLE_PRIORITY_CLASS, BELOW_NORMAL_PRIORITY_CLASS, NORMAL_PRIORITY_CLASS, // ABOVE_NORMAL_PRIORITY_CLASS, HIGH_PRIORITY_CLASS, REALTIME_PRIORITY_CLASS
return — 最推薦,正確調用析構函數、釋放棧、設置退出碼、遞減使用計數#include <stdio.h>
#include <windows.h>
DWORD WINAPI ThreadProc(LPVOID lpParam) {
for (int i = 0; i < 20; i++) {
printf("Thread running, count = %d\n", i);
}
return 0;
}
int main() {
HANDLE hThread;
DWORD dwThreadId;
hThread = CreateThread(NULL, 0, ThreadProc, NULL, 0, &dwThreadId);
printf("Thread created, ID = %d\n", dwThreadId);
WaitForSingleObject(hThread, INFINITE);
CloseHandle(hThread);
return 0;
}
DWORD WINAPI ThreadIdle(LPVOID lpParam) {
for (int i = 0; i < 10; i++) printf("Idle Thread running\n");
return 0;
}
DWORD WINAPI ThreadNormal(LPVOID lpParam) {
for (int i = 0; i < 10; i++) printf("Normal Thread running\n");
return 0;
}
int main() {
HANDLE h[2];
DWORD dwThreadId;
// Idle優先級線程:創建掛起 -> 設置優先級 -> 恢復
h[0] = CreateThread(NULL, 0, ThreadIdle, NULL, CREATE_SUSPENDED, &dwThreadId);
SetThreadPriority(h[0], THREAD_PRIORITY_IDLE);
ResumeThread(h[0]);
// Normal優先級線程:直接運行
h[1] = CreateThread(NULL, 0, ThreadNormal, NULL, 0, &dwThreadId);
// 等待兩者都結束
WaitForMultipleObjects(2, h, TRUE, INFINITE);
CloseHandle(h[0]); CloseHandle(h[1]);
return 0;
}
CREATE_SUSPENDED → 設置優先級/親和性/棧大小 → ResumeThread,避免競態CreateThread 返回句柄必須 CloseHandle,否則洩漏內核對象引用Win32線程編程的核心在於理解內核對象生命周期(使用計數、信號狀態、暫停計數)、優先級體系(進程類別+線程相對優先級)與同步原語的正確組合。牢記「自然返回是唯一正確的終止方式」,配合 _beginthreadex、CREATE_SUSPENDED、事件驅動退出模式,即可編寫健壯、高性能的多線程Windows應用。