Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1804318
  • 博文数量: 290
  • 博客积分: 10653
  • 博客等级: 上将
  • 技术积分: 3178
  • 用 户 组: 普通用户
  • 注册时间: 2007-10-24 23:08
文章存档

2013年(6)

2012年(15)

2011年(25)

2010年(86)

2009年(52)

2008年(66)

2007年(40)

分类:

2008-01-08 21:05:53

Tutorial 16: Event Object

第十六课:事件对象


We will learn what an event object is and how to use it in a multithreaded program.

我们将学习什么是一个事件对象和如何在多线程程序中使用它。

Download the example here.

Theory:

原理:

From the previous tutorial, I demonstrated how threads communicate with a custom window message. I left out two other methods: global variable and event object. We will use both of them in this tutorial.

 

在前一课中,我示范了如何用一个自定义的窗口消息来实现多线程的通讯。我留下了其它两种方法:全局变量和事件对象。我们将在这一课中用这两种方法。


An event object is like a switch: it has only two states: on or off. When an event object is turned on, it's in the "signalled" state. When it is turned off, it's in the "nonsignalled" state. You create an event object and put in a code snippet in the relevant threads to watch for the state of the event object. If the event object is in the nonsignalled state, the threads that wait for it will be asleep.When the threads are in wait state, they consume little CPU time.

一个事件对象如同一个开关:它仅有两种状态:开和关。当一个事件对象状态变为开时,它处于“有信号”状态。当它为关时,它处于“无信号状态”你创建一个事件对象并把它放置在和线程相关的代码片段中,线程等待这事件对象的状态。如果事件对象处于无信号状态,等待的线程将睡眠。当线程在等待态时,它消耗的CPU时间就小得多了。

 

You create an event object by calling CreateEvent function which has the following syntax:

你可以通过调用CreateEvent函数来创建一个事件对象,这个函数句法如下:

CreateEvent proto lpEventAttributes:DWORD,\
                              bManualReset:DWORD,\
                              bInitialState:DWORD,\
                              lpName:DWORD

lpEventAttribute--> If you specify NULL value, the event object is created with default security descriptor.

lpEventAttribute-->如果你指定的值为空(NULL),被创建的对象具有默认的安全性描述。
bManualReset--> If you want Windows to automatically reset the event object to nonsignalled state after WaitForSingleObject call, you must specify FALSE as this parameter. Else you must manually reset the event object with the call to ResetEvent.

bManualReset-->如果想在调用了WaitForSIngleObject函数后想让windows自动复位事件对象的状态为“无信号”状态,你必须指定FALSE作为这个参数的值。否则你必须调用ResetEvent函数来手动复位这个事件对象。


bInitialState--> If you want the event object to be created in the signalled state, specify TRUE as this parameter else the event object will be created in the nonsignalled state.

bInitialState-->如果你想让创建的事件对象处于“有信号状态中,指定TURE作为这个参数的参数值,否则这个事件对象将在被创建后进入”无信号状态“。
lpName --> Pointer to an ASCII string that is the name of the event object. This name is used when you want to call OpenEvent.

lpName -->指向一个ASCII 字符串的指针。字符是事件对象的名称。当你想调用OpenEvent函数时,这个名字将被使用。

If the call is successful, it returns the handle to the newly created event object else it returns NULL.
You can modify the state of an event object with two API calls: SetEvent and ResetEvent. SetEvent function sets the event object into signalled state. ResetEvent does the reverse.

如果这个调用是成功的,它返回一个新创建的事件对象句柄,否则它的返回值为空(NULL)。                                                           你能调用两个API函数来修改一个事件对象的状态: SetEvent ResetEvent函数。SetEvent函数设置事件对象进入有信号状态。ResetEvent功能和SetEvent相反。


When the event object is created, you must put the call to WaitForSingleObject in the thread that wants to watch for the state of the event object. WaitForSingleObject has the following syntax:

当事件对象被创建时,你必须把WaitForSingleObject函数放置于想等待事件对象状态的线程中。WaitForSingleObject句法如下:

WaitForSingleObject proto hObject:DWORD, dwTimeout:DWORD

hObject --> A handle to one of the synchronization object. Event object is a type of synchronization object.

hObject -->同步对象的一个句柄,事件对象属于同步对象的一种。


dwTimeout --> specify the time in milliseconds that this function will wait for the object to be in signalled state. If the specified time has passed and the event object is still in nonsignalled state, WaitForSingleObject returns the the caller. If you want to wait for the object indefinitely, you must specify the value INFINITE as this parameter.

dwTimeout -->以毫秒为单位指定一个时间值,这个时间值是函数等待事件对象进入有信号状态的时间。如果指定的时间已经过了而事件对象还处于无信号状态,WaitForSingleObject将返回给调用者。如果你想不确定的等待事件对象,你必须指定INFINITE作为这个参数的值。

Example:

The example below displays a window waiting for the user to select a command from the menu. If the user selects "run thread", the thread starts the savage calculation. When it's finished, a message box appears informing the user that the job is done. During the time that the thread is running, the user can select "stop thread" to stop the thread.

下面的例子将显示一个窗口并等待用户从菜单中选择一个命令。如果用户选择“Run thread“,这个线程开始原始计算。当它完成后,弹出一个消息框通知用户工作已经完成。在线程运行的那段时间,用户能选择”stop thread” 来终止线程。

.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
includelib \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 "The thread is stopped",0
EventStop BOOL FALSE

.data?
hInstance HINSTANCE ?
CommandLine LPSTR ?
hwnd HANDLE ?
hMenu HANDLE ?
ThreadID DWORD ?
ExitCode DWORD ?
hEventStart HANDLE ?

.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
    .WHILE 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, I demonstrate another thread technique.

    .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

You can see that I create the event object and the thread during the processing of WM_CREATE message. I create the event object in the nonsignalled state with automatic reset. After the event object is created, I create the thread. However the thread doesn't run immediately because it waits for the event object to be in the signalled state as the code below:

你能看到,在处理WM_CREATE消息区间,我创建了事件对象和线程。我创建的事件对象为无信号状态并让windows自动复位它。在事件对象被创建后,我创建了线程。然而,这个线程并没有立即运行,因为它要等到事件对象的状态为有信号时才执行,代码如下:

ThreadProc PROC USES ecx Param:DWORD
        invoke WaitForSingleObject,hEventStart,INFINITE
        mov  ecx,600000000

The first line of the thread procedure is the call to WaitForSingleObject. It waits infinitely for the signalled state of the event object before it returns. This means that even when the thread is created, we put it into a dormant state.

第一行是调用WaitForSIngleObject API函数的线程处理程序。在它返回之前,它将无限的等待事件对象到有信号状态。这意味着,即使是线程被创建,我们也将让它进入等待态。
When the user selects "run thread" command from the menu, we set the event object into signalled state as below:

当用户从菜单中选择了“run thread “命令,我们设置事件对象进入到有信号状态的代码如下:

            .if ax==IDM_START_THREAD
                invoke SetEvent,hEventStart

The call to SetEvent turns the event object into the signalled state which in turn makes the WaitForSingleObject call in the thread procedure return and the thread starts running. When the user selects "stop thread" command,  we set the value of the global variable "EventStop" to TRUE.

SetEvent这个调用改变事件对象的状态让事件对象进入到有信号状态。这种状态能让WaitForSingleObject函数调用在线程过程中返回并且让线程开始运行。当用户选择了“stop thread ”命令时,我们设置全局变量“EventStop”的值为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 stops the thread and jumps to the WaitForSingleObject call again. Note that we don't have to manually reset the event object into nonsignalled state because we specify the bManualReset parameter of the CreateEvent call as FALSE.

这是终止线程并且跳转到WaitForSingleObject调用处。注意:我们并不需要手动恢复事件对象进入无信号状态,因为我们调用CreateEvent函数时指定了它的bManualReset参数的值为FALSE


This article come from Iczelion's asm page

                   风向改变翻译于2008-1-8日晚

 

文件: tut16.zip
大小: 3KB
下载: 下载

阅读(1566) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~