在Win32环境下编写多线程应用程序,经常要用到事件对象Event,来进行线程同步。与其相关的一组API包括:CreateEvent,SetEvent,ResetEvent,WaitForSingleObject,和CloseHandle。关于这些API的功能以及参数意义等这里就不多说了。下边,我封装了一个事件对象类,以及测试代码。已由本人在VS2005环境下编译,测试通过。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 |
//MyEvent.h #ifndef My_Event_Header #define My_Event_Header #include <iostream> #ifdef WIN32 #include <Windows.h> #endif using namespace std; //--------------------------------------------------------------- class CEventImpl { protected: /* 创建一个匿名事件对象 `bAutoReset true 人工重置 false 自动重置 */ CEventImpl(bool bManualReset); /* 销毁一个事件对象 */ ~CEventImpl(); /* 将当前事件对象设置为有信号状态 若自动重置,则等待该事件对象的所有线程只有一个可被调度 若人工重置,则等待该事件对象的所有线程变为可被调度 */ void SetImpl(); /* 以当前事件对象,阻塞线程,将其永远挂起 直到事件对象被设置为有信号状态 */ bool WaitImpl(); /* 以当前事件对象,阻塞线程,将其挂起指定时间间隔 之后线程自动恢复可调度 */ bool WaitImpl(long lMilliseconds); /* 将当前事件对象设置为无信号状态 */ void ResetImpl(); private: HANDLE h_Event; }; inline void CEventImpl::SetImpl() { if (!SetEvent(h_Event)) { cout<<"cannot signal event"<<endl; } } inline void CEventImpl::ResetImpl() { if (!ResetEvent(h_Event)) { cout<<"cannot reset event"<<endl; } } //--------------------------------------------------------------- class CMyEvent: private CEventImpl { public: CMyEvent(bool bManualReset = true); ~CMyEvent(); void Set(); bool Wait(); bool Wait(long milliseconds); bool TryWait(long milliseconds); void Reset(); private: CMyEvent(const CMyEvent&); CMyEvent& operator = (const CMyEvent&); }; inline void CMyEvent::Set() { SetImpl(); } inline bool CMyEvent::Wait() { return WaitImpl(); } inline bool CMyEvent::Wait(long milliseconds) { if (!WaitImpl(milliseconds)) { cout<<"time out"<<endl; return false; } else { return true; } } inline bool CMyEvent::TryWait(long milliseconds) { return WaitImpl(milliseconds); } inline void CMyEvent::Reset() { ResetImpl(); } #endif |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 |
//MyEvent.cpp #include "MyEvent.h" CEventImpl::CEventImpl(bool bManualReset) { h_Event = CreateEvent(NULL, bManualReset, FALSE, NULL); if (!h_Event) cout<<"cannot create event"<<endl; } CEventImpl::~CEventImpl() { CloseHandle(h_Event); } bool CEventImpl::WaitImpl() { switch (WaitForSingleObject(h_Event, INFINITE)) { case WAIT_OBJECT_0: return true; default: cout<<"wait for event failed"<<endl; } return false; } bool CEventImpl::WaitImpl(long lMilliseconds) { switch (WaitForSingleObject(h_Event, lMilliseconds + 1)) { case WAIT_TIMEOUT: return false; case WAIT_OBJECT_0: return true; default: cout<<"wait for event failed"<<endl; return false; } } CMyEvent::CMyEvent(bool bManualReset): CEventImpl(bManualReset) { } CMyEvent::~CMyEvent() { } |
下边是测试代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 |
// CEvent.cpp : 定义控制台应用程序的入口点。 // #include "MyEvent.h" #include <process.h> #define PRINT_TIMES 10 //创建一个人工自动重置事件对象 CMyEvent g_myEvent(true); int g_iNum = 0; //线程函数1 unsigned int __stdcall ThreadProc1(void *pParam) { for (int i = 0; i < PRINT_TIMES; i++) { g_iNum++; cout<<"ThreadProc1 do print, Num = "<<g_iNum<<endl; //设置事件为有信号状态 g_myEvent.Set(); Sleep(1000); } return (unsigned int)0; } //线程函数2 unsigned int __stdcall ThreadProc2(void *pParam) { bool bRet = false; while ( 1 ) { if ( g_iNum >= PRINT_TIMES ) { break; } //以当前事件对象阻塞本线程,将其挂起 bRet = g_myEvent.Wait(); if ( bRet ) { cout<<"ThreadProc2 do print, Num = "<<g_iNum<<endl; //设置事件为无信号状态 g_myEvent.Reset(); } else { cout<<"ThreadProc2 system exception"<<endl; } } return (unsigned int)0; } int main(int argc, char* argv[]) { HANDLE hThread1, hThread2; unsigned int uiThreadId1, uiThreadId2; //创建两个工作线程 hThread1 = (HANDLE)_beginthreadex(NULL, 0, &ThreadProc1, NULL, 0, &uiThreadId1); hThread2 = (HANDLE)_beginthreadex(NULL, 0, &ThreadProc2, NULL, 0, &uiThreadId2); //等待线程结束 DWORD dwRet = WaitForSingleObject(hThread1,INFINITE); if ( dwRet == WAIT_TIMEOUT ) { TerminateThread(hThread1,0); } dwRet = WaitForSingleObject(hThread2,INFINITE); if ( dwRet == WAIT_TIMEOUT ) { TerminateThread(hThread2,0); } //关闭线程句柄,释放资源 CloseHandle(hThread1); CloseHandle(hThread2); system("pause"); return 0; } |
测试代码中使用全局事件对象g_myEvent,对线程1和2进行同步,每当线程1函数对全局变量g_iNum做加1之后,通知线程2,立即将该变量值打印出来。如此循环10,线程1和2分别结束自己。
编译,运行
Linux平台用C++实现事件对象,同步线程
发表评论
要发表评论,您必须先登录。