多執行緒程式設計中,執行緒間同步是核心課題。Windows 提供事件對象作為輕量級同步機制,本質為雙態訊號(有訊號/無訊號),類似開關。本文說明事件對象建立、狀態控制、等待機制,並以 MASM 範例展示主執行緒透過選單啟動/停止工作執行緒的完整流程。
CreateEvent proto lpEventAttributes:DWORD,
bManualReset:DWORD,
bInitialState:DWORD,
lpName:DWORD
lpEventAttributes:NULL 使用預設安全屬性bManualReset:FALSE=自動重設(WaitForSingleObject 返回後自動歸無訊號),TRUE=手動重設(需呼叫 ResetEvent)bInitialState:TRUE=初始有訊號,FALSE=初始無訊號lpName:跨程序共享時指定名稱,否則 NULL成功返回事件控制碼,失敗返回 NULL。
SetEvent(hEvent):設為有訊號ResetEvent(hEvent):設為無訊號(手動重設模式必須)WaitForSingleObject proto hObject:DWORD, dwTimeout:DWORD
hObject:同步物件控制碼(事件、執行緒、處理程序等)dwTimeout:等待毫秒數,INFINITE (0xFFFFFFFF) 表無限期等待物件變為有訊號時函式返回,執行緒繼續執行;逾時則返回 WAIT_TIMEOUT。
主視窗提供「Run Thread」與「Stop Thread」選單項。啟動時建立自動重設、初始無訊號的事件,並創建工作執行緒;工作執行緒一進入即 WaitForSingleObject(hEventStart, INFINITE) 阻塞;使用者選「Run」呼叫 SetEvent 喚醒執行緒執行 6 億次加法運算;選「Stop」設全域旗標 EventStop=TRUE,執行緒檢測到後彈出訊息並跳回等待狀態。
.IF uMsg==WM_CREATE
invoke CreateEvent, NULL, FALSE, FALSE, NULL ; 自動重設、初始無訊號
mov hEventStart, eax
mov eax, OFFSET ThreadProc
invoke CreateThread, NULL, NULL, eax, NULL, 0, ADDR ThreadID
invoke CloseHandle, eax ; 不需執行緒控制碼,立即關閉避免洩漏
ThreadProc PROC USES ecx Param:DWORD
invoke WaitForSingleObject, hEventStart, INFINITE
mov ecx, 600000000
.WHILE ecx!=0
.if EventStop!=TRUE
add eax, eax
dec ecx
.else
invoke MessageBox, hwnd, ADDR StopString, ADDR AppName, MB_OK
mov EventStop, FALSE
jmp ThreadProc ; 重新進入等待
.endif
.ENDW
invoke PostMessage, hwnd, WM_FINISH, NULL, NULL
invoke EnableMenuItem, hMenu, IDM_START_THREAD, MF_ENABLED
invoke EnableMenuItem, hMenu, IDM_STOP_THREAD, MF_GRAYED
jmp ThreadProc ; 循環等待下一次啟動
ret
ThreadProc ENDP
.ELSEIF uMsg==WM_COMMAND
mov eax, wParam
.if lParam==0
.if ax==IDM_START_THREAD
invoke SetEvent, hEventStart
invoke EnableMenuItem, hMenu, IDM_START_THREAD, MF_GRAYED
invoke EnableMenuItem, hMenu, IDM_STOP_THREAD, MF_ENABLED
.elseif ax==IDM_STOP_THREAD
mov EventStop, TRUE
invoke EnableMenuItem, hMenu, IDM_START_THREAD, MF_ENABLED
invoke EnableMenuItem, hMenu, IDM_STOP_THREAD, MF_GRAYED
.else
invoke DestroyWindow, hWnd
.endif
.endif
bManualReset=FALSE 免去手動 ResetEvent,每次 WaitForSingleObject 返回自動歸無訊號,適合「單次觸發、單次消費」模型。jmp ThreadProc 重複等待→執行→等待,避免頻繁建立/銷毀開銷。EventStop 負責「中斷」,兩者分工明確。CreateThread 返回的控制碼若不需 WaitForSingleObject 等待執行緒結束,應立即 CloseHandle 釋放核心物件參考計數。事件對象提供簡潔高效的執行緒同步原語。掌握 CreateEvent 參數含義、自動/手動重設差異、WaitForSingleObject 等待語意,結合全域旗標實現複雜控制邏輯,是 Win32 多執行緒程式設計的基本功。