代码改变世界

Windows CEvent事件

2015-02-05 14:23  sylar_liang  阅读(1083)  评论(0编辑  收藏  举报

头文件:
#include <afxmt.h>

 

CEvent类的一个对象,表示一个“事件”.事件是一个允许一个线程在某种情况发生时,唤醒另外一个线程的同步对象。

基本步骤:
1. 创建CEvent实例
2. 在启动线程A时,将该实例传入线程A
3. 在线程A结束前,调用CEvent的SetEvent()成员
4. 在启动线程B的前面,等待CEvent的实例句柄
::WaitForSingleObject(pEvent->m_hObject, INFINITE);

 

CEvent(
BOOL bInitiallyOwn /* = FALSE */ , // 用来指定事件对象初始状态是否为发信状态(默认值为未发信)
BOOL bManualReset /* = FALSE */ , // 用来指定创建的事件对象是自动事件还是手动事件对象(默认值为自动事件对象)
LPCTSTR lpszNAme /* = NULL */ , // 用来定义事件对象的名称,指定要创建的事件对象的名,如果该事件对象将跨进程使用,则此参数不能为NULL。
LPSECURITY_ATTRIBUTES lpsaAttribute /* = NULL */ // 指向一个LPSECURITY_ATTRIBUTES结构的指针
);

CEvent类提供的三种方法
SetEvent() // 设置事件为发信状态,并且释放所有等待的线程。
// 人工事件,则CEvent类对象保持为有信号状态;
// 自动事件,则在SetEvent()将事件设置为有信号状态后,CEvent类对象由系统自动重置为无信号状态,除非一个线程被释放。
// 该函数执行成功,则返回非零值,否则返回零。
PulseEvent() // 设置事件为发信状态,并释放其他正在等待的线程,然后把事件设置为未发信状态
// 发送一个事件脉冲,该函数完成一系列操作后才返回。
// 对于自动事件,PulseEvent()将事件设置为有信号状态,等待一个线程被释放,将事件重置为无信号状态,然后PulseEvent()返回;
//

ResetEvent() // 设置事件为未发信状态
// 执行成功,返回非零值,否则返回非零。

DWORD WaitForSingleObject(
HANDLE hHandle,
DWORD dwMilliseconds
);
// 自动事件,则当WaitForSingleObject(hHandle,INFINITE)返回时,自动把CEvent对象重置为无信号状态。
// CEvent::SetEvent()把对象设置为有信号状态,释放等待的线程。
// CEvent::ResetEvent()把对象设置为无信号状态,程序在WaitForSingleObject(hHandle,INFINITE)处等待。

1.自动事件
初始状态为未发信状态,可以用SetEvent使之变为发信状态。自动事件对象一次只能启动一个处于等待状态的线程。

2.手工事件
手工事件对象一旦用函数SetEvent设置为“发信”状态,就一直处于有效状态,除非又使用对象的成员函数PulseEvent或ResetEvent把它重新设置为“未发信”状态。
所以手工事件对象被用来恢复多个处在等待状态线程的运行。
CEvent eventObj(FALSE,TRUE);

 

类设计:

数据:
HANDLE m_hEvent;
函数:
CEvent(LPSECURITY_ATTRIBUTES lpsaAttribute, BOOL bManualReset, BOOL bInitialState) // 构造函数
CEvent(LPSECURITY_ATTRIBUTES lpsaAttribute, BOOL bManualReset, BOOL bInitialState, const str::sting &name)

virtual ~CEvent() // 析构函数

// 拷贝与赋值构造函数不做定义

//CEvent(const CEvent& rhs) // 拷贝构造函数

//CEvent & operator =(const CEvent& rhs) // 赋值构造函数

//
HANDLE GetEvent() const // 获取事件的句柄
void Wait() const // 等待
BOOL Wait(DWORD timeoutMullis) const // 等待
void Reset() // 重置
void Set() // 设置
void Pulse() //

// MyCEvent.h
#pragma
once #include “CommonHead.h”

class MyCEvent { public: // 构造函数 MyCEvent(LPSECURITY_ATTRIBUTES lpsaAttribute /*= NULL*/, BOOL bManualReset /*= FALSE*/, BOOL bInitialState /*= FALSE*/); MyCEvent(LPSECURITY_ATTRIBUTES lpsaAttribute, BOOL bManualReset, BOOL bInitialState, const std::string &name); virtual ~MyCEvent(); // 析构函数 //MyCEvent(const MyCEvent& rhs); // 拷贝构造函数 //MyCEvent & operator =(const MyCEvent& rhs); // 赋值构造函数 // HANDLE GetEvent() const; // 获取事件的句柄 void Wait() const; // 等待 BOOL Wait(DWORD timeoutMullis) const; // 等待 void Reset(); // 重置 void Set(); // 设置 void Pulse(); // private: HANDLE m_hEvent; // 事件句柄 };
// MyCEvent.cpp
#include "MyCEvent.h"

static HANDLE Create(LPSECURITY_ATTRIBUTES lpsaAttribute, BOOL bManualReset, BOOL bInitialState, LPCTSTR lpName);


MyCEvent::MyCEvent(LPSECURITY_ATTRIBUTES lpsaAttribute, BOOL bManualReset, BOOL bInitialState)
{
    m_hEvent = Create(lpsaAttribute, bManualReset, bInitialState, NULL);
}

MyCEvent::MyCEvent(LPSECURITY_ATTRIBUTES lpsaAttribute, BOOL bManualReset, BOOL bInitialState, const _tstring &name)
{
    m_hEvent = Create(lpsaAttribute, bManualReset, bInitialState, name.c_str());
}


MyCEvent::~MyCEvent(void)
{
}

//// 拷贝构造函数
//MyCEvent::MyCEvent(const MyCEvent& rhs)
//{
//
//}

//// 赋值构造函数
//MyCEvent & MyCEvent::operator =(const MyCEvent& rhs)
//{
//
//}

// 获取事件的句柄
HANDLE MyCEvent::GetEvent() const
{
    return m_hEvent;
}

// 等待
void MyCEvent::Wait() const
{
    Wait(INFINITE);
}

// 等待
BOOL MyCEvent::Wait(DWORD timeoutMullis) const
{
    BOOL bRet = TRUE;
    DWORD result = ::WaitForSingleObject(m_hEvent, timeoutMullis);
    if(result == WAIT_TIMEOUT)
    {
        bRet = FALSE;
    }

    return bRet;
}

// 重置
void MyCEvent::Reset() 
{
    ::ResetEvent(m_hEvent);
}

// 设置
void MyCEvent::Set()
{
    ::SetEvent(m_hEvent);
}
void MyCEvent::Pulse()
{
    ::PulseEvent(m_hEvent);
}

HANDLE Create(LPSECURITY_ATTRIBUTES lpsaAttribute, BOOL bManualReset, BOOL bInitialState, LPCTSTR lpName)
{
    HANDLE hEvent = CreateEvent(lpsaAttribute, bManualReset, bInitialState, lpName);
    if(hEvent == NULL)
        return NULL;
    else
        return hEvent;
}

 

简单例子:
#include <afxmt.h>

void fnThread1(void *ptr)
{
  MyCEvent *pEvent = (MyCEvent *)ptr;
  WaitForSingleObject(pEvent->GetEvent(), INFINITE);

  for(int i=0; i<10; ++i)
  {
    printf("Thread1 %d.\n",i);
  }
}

void fnThread2(void *ptr)
{
  MyCEvent *pEvent = (MyCEvent *)ptr;
  for( int i = 0; i < 5; i++ )
  {
    printf("ThreadFunc2:%d\n", i);
    Sleep(1000);
  }

  pEvent->Set();
}

int _tmain(int argc, _TCHAR* argv[])
{
  MyCEvent event(NULL, NULL, NULL);
  // 或者
  //MyCEvent event(NULL, TRUE, TRUE);
  //event.Reset();

  DWORD thread[2];

  ::CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)fnThread1,(LPVOID)&event,0,&thread[0]);
  ::CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)fnThread2,(LPVOID)&event,0,&thread[1]);

  getchar();
  return 0;
}

 

// 包含之前定义的线程类,线程池一起使用的例子:

int _tmain(int argc, _TCHAR* argv[])
{
    MyCEvent event(NULL, FALSE, FALSE);
    // 或下面的方式调用
    //MyCEvent event(NULL, TRUE, TRUE);
    //event.Reset();

    MyThreadPool tpool;
    CThreadTest *mythread1 = new CThreadTest(event);
    tpool.AddThread(mythread1, false);

    CThreadTest2 *mythread2 = new CThreadTest2(event);
    tpool.AddThread(mythread2, false);
    
    getchar();
    return 0;    
}

// 派生的线程类
// CThreadTest.h
#pragma once
#include "mythread.h"


class MyCEvent;

class CThreadTest :
    public MyThread
{
public:
    CThreadTest(MyCEvent & ev);
    ~CThreadTest(void);

    void endThread();
    DWORD run();

    MyCEvent & m_event;
};

// CThreadTest.cpp
#include "ThreadTest.h"
#include "MyCEvent.h"

CThreadTest::CThreadTest(MyCEvent & ev)
    :m_event(ev)
{
}

CThreadTest::~CThreadTest(void)
{
}

void CThreadTest::endThread()
{
    m_event.Set();
    WaitForSingleObject(m_event.GetEvent(),INFINITE);
}

DWORD CThreadTest::run()
{
    WaitForSingleObject(m_event.GetEvent(), INFINITE);

    for(int i=0; i<10; ++i)
    {
        printf("Thread1 %d.\n",i);
    }

    return 0;
}

// ThreadTest2.h 与 ThreadTest.h 一致
// ThreadTest2.cpp
#include "ThreadTest2.h"
#include "MyCEvent.h"

CThreadTest2::CThreadTest2(MyCEvent & ev)
    :m_event(ev)
{
}

CThreadTest2::~CThreadTest2(void)
{
}

void CThreadTest2::endThread()
{
    m_event.Set();
    WaitForSingleObject(m_event.GetEvent(),INFINITE);
}

DWORD CThreadTest2::run()
{
    for( int i = 0; i < 5; i++ )  
    {  
        printf("ThreadFunc2:%d\n", i);  
        Sleep(1000);  
    } 

    m_event.Set();
    return 0;
}