在 Windows 95 這個多工、多執行緒的作業系統中,每個應用程式本質上都是一個行程,而行程可建立多個並發執行緒。要對獨立執行的執行緒進行有效控制(如暫停、終止、條件觸發),必須在執行緒間建立同步機制。本文深入探討如何利用 Win32 API 提供的 Event 同步物件,實現執行緒間的事件同步控制,並延伸至跨行程的同步應用。
Windows 95 中的執行緒是系統排程的基本單位,以函數形式存在,共享所屬行程的全域變數、檔案控制表等資源。主執行緒類似 UNIX 的父行程,建立的子執行緒獨立運行。使用 CreateThread API 建立執行緒:
hThread = CreateThread(
NULL, // 安全屬性(僅 NT 相關)
0, // 預設堆疊大小
&ThreadFunc, // 執行緒入口函數
this, // 傳遞參數(通常為 this 指標)
0, // 建立旗標
&hThreadId // 接收執行緒 ID
);
執行緒函數通常轉呼叫類別成員函數執行具體任務:
DWORD _stdcall TEventWindow::ThreadFunc(void *thrdWin) {
return static_cast(thrdWin)->LoopFunc();
}
Win32 提供兩類同步物件:互斥類(Mutex,協調資料存取)與事件類(Event,發送命令/觸發事件、安排執行順序)。Event 物件擁有兩種狀態:Signaled(已觸發)與 Non-signaled(未觸發)。關鍵 API:
CreateEvent:建立 Event,可指定手動/自動重置、初始狀態、名稱(跨行程共享需命名)。SetEvent / ResetEvent:設定/重置狀態為 Signaled/Non-signaled。WaitForSingleObject / WaitForMultipleObjects:等待物件進入 Signaled 狀態,支援超時與多物件等待邏輯。場景:使用者關閉視窗時,必須先通知背景執行緒終止,待執行緒安全退出後才真正關閉視窗,避免執行緒繼續繪圖導致畫面錯亂。
1. 建立兩個自動重置 Event(初始 Non-signaled):
hCloseEvent = CreateEvent(0, FALSE, FALSE, 0); // 通知執行緒關閉
hNoCloseEvent = CreateEvent(0, FALSE, FALSE, 0); // 執行緒回報「暫時無法關閉」
2. 主執行緒關閉流程:
BOOL TEventWindow::CanClose() {
HANDLE Signals[2] = { hThread, hNoCloseEvent };
SetEvent(hCloseEvent); // 發出關閉通知
// 等待:執行緒結束 或 執行緒回報無法關閉
if (WaitForMultipleObjects(2, Signals, FALSE, INFINITE) == 0)
return TRUE; // 執行緒已結束,可關閉
else
return FALSE; // 執行緒回報無法關閉,暫不關閉視窗
}
3. 背景執行緒循環處理:
DWORD TEventWindow::LoopFunc() {
HANDLE Signals[3] = { hCloseEvent, hWatchEvent, hNoBlockEvent };
static BOOL bWatch = FALSE;
int dwEvent;
while (1) {
dwEvent = WaitForMultipleObjects(3, Signals, FALSE, INFINITE);
switch (dwEvent) {
case 0: // 收到關閉通知
if (iCount > 100) return 0; // 滿足條件,結束執行緒
else SetEvent(hNoCloseEvent); // 否則回報無法關閉
break;
case 1: // 收到監看通知
bWatch = TRUE;
break;
case 2: // 無封鎖事件(hNoBlockEvent 永遠 Signaled)
++iCount;
if (bWatch && iCount > 200) SetEvent(hNtyEvent); // 觸發主執行緒繼續
break;
}
}
}
關鍵設計:hNoBlockEvent 為手動重置且初始 Signaled,確保無使用者控制事件時執行緒仍能持續運行。WaitForMultipleObjects 依陣列順序檢查,優先響應使用者控制事件。
Event 物件在系統範圍內有效。另一行程可透過 OpenEvent 取得已命名 Event 的句柄,進而呼叫 SetEvent、ResetEvent、WaitForMultipleObjects 等函數,實現跨行程的執行緒控制。例如:
HANDLE hEvent = OpenEvent(EVENT_ALL_ACCESS, TRUE, "MyEvent");
ResetEvent(hEvent); // 讓對方執行緒暫停
SetEvent(hEvent); // 讓對方執行緒繼續
這使得不同應用程式間的同步控制變得簡單直觀。
SignalsL)至關重要。TerminateThread 強制終止,應採用事件通知協同結束,確保資源正確釋放。善用 Event 物件,能構建出健壯、可控的多執行緒應用程式架構。