《windows sdk编程系列文章13 ---- 事件对象.doc》由会员分享,可在线阅读,更多相关《windows sdk编程系列文章13 ---- 事件对象.doc(9页珍藏版)》请在taowenge.com淘文阁网|工程机械CAD图纸|机械工程制图|CAD装配图下载|SolidWorks_CaTia_CAD_UG_PROE_设计图分享下载上搜索。
1、windows sdk编程系列文章 - 事件对象2008-04-13 22:12本课中我们将要学习事件对象以及如何在多线程编程中如何使用同步对象。 理论:上一课中我们演示了如何用WINDOWS消息在不同的线程之间进行通讯。另外的两种,即:使用全局变量和事件对象,将在本课中讲解。 事件对象就像一个开关:它只有两种状态-开和关。当一个事件处于”开”状态,我们称其为”有信号”否则称为”无信号”。您可以在一个线程的执行函数中创建一个事件对象,然后观察它的状态,如果是”无信号”就让该线程睡眠,这样该线程占用的CPU时间就比较少。 产生事件对象的函数如下: HANDLE CreateEvent( LPSE
2、CURITY_ATTRIBUTES lpEventAttributes, BOOL bManualReset, BOOL bInitialState, LPCTSTR lpName );lpEventAttribute- 如果是NULL值,产生的事件对象有缺省的安全属性。bManualReset- 如果想在每次调用WaitForSingleObject 后让WINDOWS为您自动地把事件地状态恢复为”无信号”状态,必须把该参数设为FALSE,否则,您必须每次调用ResetEvent函数来清除事件的信号。bInitialState- 刚刚产生事件对象时的状态。如果设为TRUE是”有信号”,否则是
3、”无信号”。lpName - 事件对象的名称。您在OpenEvent函数中可能使用。如果CreateEvent调用成功的话,会返回新生成的对象的句柄,否则返回NULL。这里有两个API函数用来修改事件对象的信号状态:SetEvent和ResetEvent。前者把事件对象设为”有信号”状态,而后者正好相反。在事件对象生成后,必须调用WaitForSingleObject来让线程进入等待状态,该函数的语法如下:DWORD WaitForSingleObject( HANDLE hHandle, DWORD dwMilliseconds );hHandle-指向同步对象的指针。事件对象其实是同步对象
4、的一种。dwMilliseconds- 等待同步对象变成”有信号”前等待的时间,以毫秒计。当等待的时间超过该值后无信号同步对象仍处于”无信号”状态,线程不再等待,WaitForSingleObject函数会返回。如果想要线程一直等待,请把该参数设为INFINITE(该值等于0xffffffff)。例子:见光盘FirstWindow14下面的例子显示了一个窗口,当用户选择了菜单项”run thread”后,线程开始简单的计数运算。结束后弹出一个对话框通知用户。在整个的计数期间,您可以选择菜单项”stop thread”来随时终止线程。#include Windows.h#include tcha
5、r.hTCHAR ClassName = _T(Win32EventClass);TCHAR AppName = _T(Win32 Event Example);TCHAR MenuName = _T(FirstMenu);TCHAR SuccessString = _T(The calculation is completed!);TCHAR StopString = _T(The thread is stopped);BOOL EventStop;HINSTANCE g_hInstance;#define IDM_START_THREAD 1#define IDM_STOP_THREAD
6、2#define IDM_EXIT 3#define WM_FINISH WM_USER+0x100HMENU hMenu;DWORD ExitCode;DWORD ThreadID;HWND g_hwnd;HANDLE hThread;HANDLE hEventStart;DWORD WINAPI ThreadProc(LPVOID lpParameter) int i; int tmp; while(1) START: WaitForSingleObject(hEventStart,INFINITE); i = 600000000; while(i!=0) if(EventStop = F
7、ALSE) tmp += tmp; i-; else MessageBox(g_hwnd,StopString,AppName,MB_OK); EventStop = FALSE; goto START; PostMessage(g_hwnd,WM_FINISH,NULL,NULL); EnableMenuItem(hMenu,IDM_START_THREAD,MF_ENABLED); EnableMenuItem(hMenu,IDM_STOP_THREAD,MF_GRAYED); return 0; INT_PTR CALLBACK ProcWinMain( HWND hWnd, UINT
8、Msg, WPARAM wParam, LPARAM lParam ) switch(Msg) case WM_CREATE: hEventStart = CreateEvent(NULL,FALSE,FALSE,NULL); hThread = CreateThread(NULL,NULL,ThreadProc,NULL,NORMAL_PRIORITY_CLASS,&ThreadID); break; case WM_FINISH: MessageBox(NULL,SuccessString,AppName,MB_OK); break; case WM_DESTROY: PostQuitMe
9、ssage(0); break; case WM_COMMAND: if(lParam = 0) if(LOWORD(wParam) = IDM_START_THREAD) SetEvent(hEventStart); EnableMenuItem(hMenu,IDM_START_THREAD,MF_GRAYED); EnableMenuItem(hMenu,IDM_STOP_THREAD,MF_ENABLED); else if(LOWORD(wParam) = IDM_STOP_THREAD) EventStop = TRUE; EnableMenuItem(hMenu,IDM_START
10、_THREAD,MF_ENABLED); EnableMenuItem(hMenu,IDM_STOP_THREAD,MF_GRAYED); else DestroyWindow(hWnd); break; default: return DefWindowProc(hWnd,Msg,wParam,lParam); return 0;int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) WNDCLASSEX wc; MSG msg; HWND hWnd; g
11、_hInstance = hInstance; wc.cbSize = sizeof(WNDCLASSEX); wc.style = CS_HREDRAW | CS_VREDRAW; wc.lpfnWndProc = ProcWinMain; wc.cbClsExtra = NULL; wc.cbWndExtra = NULL; wc.hInstance = hInstance; wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); wc.lpszMenuName = MenuName; wc.lpszClassName = ClassName; wc.
12、hIcon = wc.hIconSm = LoadIcon(NULL,IDI_APPLICATION); wc.hCursor = LoadCursor(NULL,IDC_ARROW); RegisterClassEx(&wc); hWnd = CreateWindowEx(WS_EX_CLIENTEDGE,ClassName,AppName,WS_OVERLAPPEDWINDOW, CW_USEDEFAULT,CW_USEDEFAULT,300,200,NULL,NULL,hInstance,NULL); g_hwnd = hWnd; ShowWindow(hWnd,SW_SHOWNORMA
13、L); UpdateWindow(hWnd); hMenu = GetMenu(hWnd); while(GetMessage(&msg,NULL,0,0) TranslateMessage(&msg); DispatchMessage(&msg); return msg.wParam;分析:本例中,我们演示另一种技巧: case WM_CREATE: hEventStart = CreateEvent(NULL,FALSE,FALSE,NULL); hThread = CreateThread(NULL,NULL,ThreadProc,NULL,NORMAL_PRIORITY_CLASS,&
14、ThreadID); break;在WM_CREATE 消息的处理中我们生成事件同步对象并创建线程。我们设置了相关的值让同步对象生成时处于”无信号”状态而且在调用了WaitForSingleObject后可以自动把事件对象的状态设为”无信号”。然后我们创建线程。 线程的代码开始执行后立即被阻塞:START: WaitForSingleObject(hEventStart,INFINITE); i = 600000000;您可以看到线程的执行体的第一条代码就是调用WaitForSingleObject函数,该函数使得线程阻塞并且一直处于等待事件对象变成”有信号”。这也就是说,我们以开始就让该线程
15、进入了睡眠状态。 当用户选择了菜单项”run thread”后,我们把事件对象得状态变成”有信号”: if(LOWORD(wParam) = IDM_START_THREAD) SetEvent(hEventStart);函数SetEvent可以让同步对象变成”有信号”状态,那么下一次线程得到时间片运行时,WaitForSingleObject函数就会返回,线程余下的代码就可以得到执行了。当用户选择了菜单项”stop thread” 时,我们把全局变量EventStop设为TRUE。 if(EventStop = FALSE) tmp += tmp; i-; else MessageBox(g_hwnd,StopString,AppName,MB_OK); EventStop = FALSE; goto START; 这样线程得计数工作结束,然后跳转到重新执行WaitForSingleObject函数的地方。注意:我们不用手动清除事件对象的信号,因为在调用CreateEvent函数时把参数bManualReset的值设为了FALSE。技