用C++实现Win32事件对象,同步线程

     在Win32环境下编写多线程应用程序,经常要用到事件对象Event,来进行线程同步。与其相关的一组API包括:CreateEvent,SetEvent,ResetEvent,WaitForSingleObject,和CloseHandle。关于这些API的功能以及参数意义等这里就不多说了。下边,我封装了一个事件对象类,以及测试代码。已由本人在VS2005环境下编译,测试通过。

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

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()
{
}


    下边是测试代码

// 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分别结束自己。

    编译,运行

用C++实现Win32事件对象,同步线程_第1张图片

 

    欢迎转载!麻烦带上链接:chexlong的专栏,谢谢合作!

 

 

你可能感兴趣的:(C++,object,测试,null,System,Signal)