Sixteenth lesson event object
In this lesson, we will learn event objects and how to use synchronous objects in multi-threaded programming.
Theory: In the previous lesson, we demonstrate how to communicate between different threads with Windows messages. In addition, use global variables and event objects, will explain in this lesson.
Event objects is like a switch: it has only two states --- open and close. When an event is in a "open" state, we call it "signal" otherwise referred to as "no signal." You can create an event object in a thread execution function, then observe its state, if it is "no signal", let the thread sleep so that the CPU time occupied by the thread is relatively small.
The function of generating an event object is as follows:
CreateEvent Proto Lpeventattributes: DWORD, / BMANUALRESET: DWORD, / BINITIALSTATE: DWORD, / LPNAME: DWORD
LPEVENTATTRIBUTE -> If it is a null value, the generated event object has the default security attribute. BmanualReset -> If you want to let Windows automatically return the event status to "No Signal" status after each call WaitForsingleObject, you must set this parameter to false, otherwise you must call the resetEvent function each time to clear the event. signal of. BinitialState -> The status when you have just generated an event object. If set to TRUE is "with signal", it is "no signal". LPNAME -> The name of the event object. You may use in the OpenEvent function.
If the CreateEvent is successful, return the handle of the newly generated object, otherwise returns NULL. Here are two API functions to modify the signal status of the event object: STEVENT and RESETEVENT. The former set the event object to "thereto" status, and the latter is just the opposite. After the event object is generated, WaitForsingleObject must be called to let the thread enter the waiting state, the syntax of the function is as follows:
WaitforsingleObject Proto Hobject: DWORD, DWTIMEOUT: DWORD
HOBJECT -> Pointer to synchronize objects. Event object is actually one of synchronous objects. DWTIMEOUT -> Waiting for synchronization objects to turn to "Signal" to wait for time, in milliseconds. When the waiting time exceeds the value, the signal is still in the "no signal" state, the thread is no longer waiting, the waitforsingleObject function will return. If you want the thread waiting, set this parameter to infinite (this value is equal to 0xfffffffff).
Example: The following example shows a window, when the user selects the menu item "Run Thread", the thread starts a simple count operation. The dialog box will notify the user after the end. During the entire count, you can select the menu item "Stop Thread" to terminate the thread at any time.
.386 .model flat, stdcall option casemap: none WinMain proto: DWORD,: DWORD,: DWORD,: DWORD include /masm32/include/windows.inc include /masm32/include/user32.inc include / masm32 / include / kernel32. Inc includelib /masm32/lib/user32.lib incruDelib /masm32/lib/kernel32.lib
.const IDM_START_THREAD equ 1 IDM_STOP_THREAD equ 2 IDM_EXIT equ 3 WM_FINISH equ WM_USER 100h.data ClassName db "Win32ASMEventClass", 0 AppName db "Win32 ASM Event Example", 0 MenuName db "FirstMenu", 0 SuccessString db "The calculation is completed! ", 0 Stopstring DB" THREAD IS Stopped ", 0 EventStop Bool False
.DATA? Hinstance Hinstance? CommandLine LPSTR? HWND HANDLE? HMENU HANDLE? Threadid DWORD? EXITCODE DWORD? HEVENTSTART HANDE?
. Code Start: Invoke GetModuleHandle, Null Mov Hinstance, Eax Invoke Getcommandline Mov Commandline, Eax Invoke Winmain, Hinstance, Null, CommandLine, SW_SHOWDEFAULT INVOKE EXITPROCESS, EAX
WinMain proc hInst: HINSTANCE, hPrevInst: HINSTANCE, CmdLine: LPSTR, CmdShow: DWORD LOCAL wc: WNDCLASSEX LOCAL msg: MSG mov wc.cbSize, SIZEOF WNDCLASSEX mov wc.style, CS_HREDRAW or CS_VREDRAW mov wc.lpfnWndProc, OFFSET WndProc mov wc. cbClsExtra, NULL mov wc.cbWndExtra, NULL push hInst pop wc.hInstance mov wc.hbrBackground, COLOR_WINDOW 1 mov wc.lpszMenuName, OFFSET MenuName mov wc.lpszClassName, OFFSET ClassName invoke LoadIcon, NULL, IDI_APPLICATION mov wc.hIcon, eax mov wc.hIconSm, eax invoke LoadCursor, NULL, IDC_ARROW mov wc.hCursor, eax invoke RegisterClassEx, addr wc invoke CreateWindowEx, WS_EX_CLIENTEDGE, aDDR ClassName, / aDDR AppName, / WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, / CW_USEDEFAULT, 300,200, NULL, NULL, / hInst , Null Mov HWnd, Eax Invoke ShowWindow, Hwnd, SW_SHOWNORMAL INVOKE UPDATEWINDOW, HWND INVOKE GETMENU, HWND MOV HMENU, EAX .Whil E True Invoke GetMessage, Addr MSG, NULL, 0, 0.Break .if (! EAX) Invoke TranslateMessage, Addr Msg Invoke DispatchMessage, Addr Msg .Endw Mov EAX, MSG.WParam Ret Winmain Endp
WndProc proc hWnd: HWND, uMsg: UINT, wParam: WPARAM, lParam: LPARAM .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 .ELSEIF uMsg == WM_DESTROY invoke PostQuitMessage, NULL .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 .ELSEIF uMsg == WM_FINISH invoke MessageBox, NULL, ADDR SuccessString, ADDR AppName, MB_OK .ELSE invoke DefWindowProc, hWnd, uMsg, wParam, lParam ret .ENDIF xor eax, eax ret WndProc endp
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 end start analysis: in this example, we demonstrate Another trick:
.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
In the process of the WM_CREATE message, we generate event synchronization objects and create threads. We set the relevant value to make the synchronous objects are generated in the "no signal" state and can automatically set the status of the event object to "no signal" after calling WaitForsingleObject. Then we create threads. The thread's code is immediately blocked immediately:
ThreadProc Proc Uses ECX Param: DWORD INVOKE WAITFORSINGLEOBJECT, HEVENTSTART, INFINITE MOV ECX, 600000000
You can see the first code of the thread's executive is to call the WaitForsingleObject function, which causes the thread to block and always wait for the event object to become "signal." That is to say, let's start to get the thread into the sleep state. When the user selects the menu item "Run Thread", we turn the event object to "Signal":
.IF AX == idm_start_thread invoke setevent, HEVENTSTART
Function setEvent allows synchronization objects to "have signal" status, then the next thread gets the time slice running, the waitforsingleObject function will return, the code under the losses can be executed. When the user selects the menu item "Stop Thread", we set the global variable eventStop to True.
.if EventStop == FALSE add eax, eax dec ecx .else invoke MessageBox, hwnd, ADDR StopString, ADDR AppName, MB_OK mov EventStop, FALSE jmp ThreadProc .endif this thread was the end of the counting operation, then jumps to re-execute the function WaitForSingleObject local. Note: We don't have to manually clear the signal of the event object, because the value of the parameter BmanualReset is set for False when calling the CreateEvent function.