• 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函数设置为无信号以后,线程函数停止运行。

     

     

  • 相关阅读:
    Linux下MySQL主从同步配置
    Tortoisegit图文使用教程
    C语言I博客作业06
    第十周助教总结
    C语言I博客作业04
    C语言I博客作业02
    第十一周助教总结
    第十二周助教总结
    第九周助教总结
    C语言I博客作业02
  • 原文地址:https://www.cnblogs.com/leven20061001/p/2750036.html
Copyright © 2020-2023  润新知