Event对象

   最近有使用到event对象,但是对event没有接触过,这里简单的学习一下。先看函数原型:

  HANDLE CreateEvent(
    LPSECURITY_ATTRIBUTES lpEventAttributes,// 安全属性,NULL为默认的安全属性
    BOOL bManualReset,// 复位方式,TRUE为手动复位,FALSE为自动复位
    BOOL bInitialState,// 初始状态,TRUE为初始为有信号,FALSE为无信号
    LPCTSTR lpName // 对象名称
  );

   对于复位的方式,提供了手动和自动,自动方式复位是事件被一个等待的线程释放以后,系统会自动将事件设置为无信号状态。手动的意思是你需要设置函数对对象进行复位为无信号,这里有两个函数可以实现:SetEvent()和ResetEvent(),函数原型如下:

BOOL SetEvent(HANDLE hEvent)
{
}

设置事件对象为有信号,如果成功,就返回非零值,如果失败返回0.

BOOL ResetEvent(HANDLE hEvent)
{
}

设置事件对象为无信号,如果成功,就返回非零值,如果失败返回0.

     一般情况下,事件对象只会在多线程使用,是系统的内核对象。线程本身就是一个死循环,如果我们想要它以某种合适条件退出,Windows会用到event对象,当然还有其他方式。具体是在线程的死循环中不断的调用WaitForSingleObject()或WaitForMultipleObjects()来检查事件是否满足条件,满足就退出线程,不满足就继续运行。这边提到上面的两个函数,介绍一下:

  DWORD WINAPI WaitForSingleObject(
  __in HANDLE hHandle,   //可以指定一系列的对象,如Event、Job、Memory resource notification、Mutex、Process、Semaphore、Thread、Waitable timer等。
  __in DWORD dwMilliseconds //定时时间间隔,单位为毫秒.INFINE无限等待直到hHandle变为有信号。如果为0,函数不会进入等待,直接返回。
  );

  返回值:

    WAIT_ABANDONED 0x00000080:当hHandle为mutex时,如果拥有mutex的线程在结束时没有释放核心对象会引发此返回值。

  WAIT_OBJECT_0 0x00000000 :核心对象已被激活

  WAIT_TIMEOUT 0x00000102:等待超时

  WAIT_FAILED 0xFFFFFFFF :出现错误,可通过GetLastError得到错误代码

  DWORD WaitForMultipleObjects(
  DWORD nCount,                   //事件个数
  const HANDLE* lpHandles,        //事件数组指针
  BOOL bWaitAll,                  //如果为false,其返回值减去WAIT_OBJECT_0就是lpHandles数组的序号;如果有多个内核事件被触发,将返回序号最小的那个。
                                      如果为true,将等待所有的事件变为有信号才往下执行。
  DWORD dwMilliseconds
  );

    由于多个内核对象被触发时,WaitForMultipleObjects选择其中序号最小的返回。而WaitForMultipleObjects它只会改变使它返回的那个内核对象的状态。这样就产生了序号小的频繁被触发,序号大永远得不到处理,需要用双WaitMultipleObjects来解决:

DWORD WINAPI ThreadProc(LPVOID lpParameter)
{
 DWORD dwRet = 0;
 int nIndex = 0;
 while(1)
 {
     dwRet = WaitForMultipleObjects(nCount,pHandles,false,INFINITE);
  switch(dwRet)
  {
  case WAIT_TIMEOUT:
        break;
  case WAIT_FAILED:
        return 1;
  default:
       {
            nIndex = dwRet - WAIT_OBJECT_0;
            ProcessHanlde(nIndex++);
            //同时检测其他的事件
            while(nIndex < nCount) //nCount事件对象总数
           {
               dwRet = WaitForMultipleObjects(nCount - nIndex,&pHandles[nIndex],false,0);
               switch(dwRet)
               {
               case WAIT_TIMEOUT:
                        nIndex = nCount; //退出检测,因为没有被触发的对象了.
                        break;
               case WAIT_FAILED:
                        return 1;
               default:
                      {
                          nIndex = nIndex + dwRet - WAIT_OBJECT_0;
                          ProcessHanlde(nIndex++);
                      }
                       break;
               }
         }
  }
  break;
   }
  }
  return 0;
}

这里,写一个简单的程序做示范:

// EventTest.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include <Windows.h>
#include <iostream>

using namespace std;

HANDLE hEvent = NULL;
HANDLE hThread = NULL;

DWORD WINAPI threadProc(LPVOID lpThreadParameter)
{
    int count = 0;
    while(1)
    {
        //Sleep(1000);
        count++;
        DWORD dw = WaitForSingleObject(hEvent, INFINITE);
        cout<<"I'm not waiting "<<count<<"s"<<endl;
    } 
    return 0;
}

int _tmain(int argc, _TCHAR* argv[])
{
    int count = 0;
    hEvent = CreateEvent(NULL, TRUE, TRUE, NULL);
    hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)threadProc, NULL, 0, NULL);

    while(1)
    {
        count++;
        DWORD dw = WaitForSingleObject(hEvent, INFINITE);
        if(dw != WAIT_OBJECT_0)
        {
            cout<<"Faile to wait!"<<endl;
            return -1;
        } 
        if(count == 1)
        {
            SetEvent(hEvent); 
        }
        if(count == 500)
        {
            ResetEvent(hEvent);
        }
    }
    cout<<count<<endl; 
    CloseHandle(hEvent);
    CloseHandle(hThread);
    system("pause");
    return 0;
}

上面只是简单地创建一个线程,并使用WaitForSingleObject()等待事件,然后返回到线程函数运行,知道ResetEvent函数设置为无信号以后,线程函数停止运行。

 

 

posted @ 2012-11-01 18:00  拿枪的程序员  阅读(793)  评论(0编辑  收藏  举报