• CreateEvent、SetEvent、ResetEvent和WaitForSingleObject


    事件对象就像一个开关:它仅仅有两种状态---开和关。当一个事件处于”开”状态。我们称其为”有信号”。否则称为”无信号”。

    能够在一个线程的运行函数中创建一个事件对象。然后观察它的状态,假设是”无信号”就让该线程睡眠。这样该线程占用的CPU时间就比較少。


    产生事件对象的函数例如以下:

    (1)CreateEvent
    函数原型:

    HANDLE CreateEvent(   
        LPSECURITY_ATTRIBUTES lpEventAttributes, // 安全属性   
        BOOL bManualReset, // 复位方式   
        BOOL bInitialState, // 初始状态   
        LPCTSTR lpName // 对象名称   
    ); 

          该函数创建一个Event同步对象,假设CreateEvent调用成功的话,会返回新生成的对象的句柄。否则返回NULL。
          lpEventAttributes:一般为NULL  
          bManualReset:指定将事件对象创建成手动复原还是自己主动复原。

    假设是TRUE(手动),那么就算等待线程处理了,必须用ResetEvent函数来手工才干将事件的状态复原到无信号状态。假设设置为FALSE(自己主动),当事件被一个等待线程处理并释放以后,系统会自己主动将事件状态复原为无信号状态。所以两者可用于不同的场合,自己主动复位的须要每次的事件信号才会执行,而手动复位的则能够一直执行。
          bInitialState:指定事件对象的初始状态。假设为TRUE。初始状态为有信号状态;否则为无信号状态。
          lpName:指定事件的对象的名称,在OpenEvent函数中可能使用。


          

           演示样例代码:// 创建一个有名的。不能被继承的,手动复原,初始状态是无信号状态的事件对象:
           Handle h = CreateEvent(NULL,TRUE,FALSE,“MyEvent”);

             一个Event被创建以后,能够用OpenEvent()API来获得它的Handle,用CloseHandle()来关闭它,用SetEvent()或PulseEvent()来设置它使其有信号,用ResetEvent()来使其无信号,用WaitForSingleObject()或WaitForMultipleObjects()来等待其变为有信号.。

     

    (2)SetEvent

    函数原型:
    BOOL WINAPI SetEvent(
          __in  HANDLE hEvent
    );
    设置事件的状态为有标记。

    假设事件创建时是手工的,此事件将保持有标记直到调用ResetEvent。

    假设事件是自己主动的,此事件将保持有标记,直到一个线程被释放,系统将设置事件的状态为无标记。

    (3)ResetEvent

    函数原型:
    BOOL ResetEvent(   
         HANDLE hEvent   
    ); 
    hEvent 指向事件对象的句柄。由 CreateEvent or OpenEvent 函数返回。这个句柄须要拥有EVENT_MODIFY_STATE 訪问权限。

    函数成功,返回非0值,否则返回0值,能够调用GetLastError得到错误的具体信息。 
          这个函数用于手动重置事件对象。手动重置的对象在线程释放后必须手动置为无信号状态。自己主动重置的事件对象在一个等待它成功的线程释放后会自己主动变为无信号状态。

    重置一个无信号的事件对象没有不论什么效果。

    (4)WaitForSingleObject

    函数原型:
    DWORD WaitForSingleObject( 

          HANDLE hHandle, 

          DWORD dwMilliseconds

    );
    參数hHandle是一个事件的句柄,第二个參数dwMilliseconds是时间间隔。假设事件是有信号状态返回WAIT_OBJECT_0。假设事件超过dwMilliseconds值但事件还是无信号状态,则返回WAIT_TIMEOUT。之前线程会一直堵塞程序在该语句处。


    举例:

    #include <windows.h>
    #include <iostream>
    #include <string>
    #include <vector>
    using namespace std;
    
    //通过事件得知还有一个线程的内部状态
    //例:线程内部有三种状态:起床 吃饭 上班
    HANDLE getupHandle;
    HANDLE breakfastHandle;
    HANDLE workHandle;
    
    vector<string> stateTexts;
    DWORD WINAPI Worker(LPVOID n);
    
    int main()
    {
    	stateTexts.reserve(3);//容器预留空间
    	getupHandle = CreateEvent(NULL, TRUE, FALSE, NULL);//手动。无信号
    	breakfastHandle = CreateEvent(NULL, TRUE, FALSE, NULL);
    	workHandle = CreateEvent(NULL, TRUE, FALSE, NULL);
    
    	DWORD threadId;
    	HANDLE threadHandle = CreateThread(NULL,
    		0,
    		Worker,//线程入口函数
    		0,
    		0,
    		&threadId);
    
    	WaitForSingleObject(getupHandle, INFINITE);
    	cout << stateTexts[0] << endl;
    	WaitForSingleObject(breakfastHandle, 3000);
    	cout << stateTexts[1] << endl;
    	WaitForSingleObject(workHandle, INFINITE);
    	cout << stateTexts[2] << endl;
    
    	CloseHandle(threadHandle);
    	CloseHandle(getupHandle);
    	CloseHandle(breakfastHandle);
    	CloseHandle(workHandle);
    
    	system("pause");
    }
    
    DWORD WINAPI Worker(LPVOID n)
    {
    	stateTexts.push_back("GetUp");
    	SetEvent(getupHandle);
    	stateTexts.push_back("Breakfast");
    	ResetEvent(breakfastHandle);
    	stateTexts.push_back("Work");
    	SetEvent(workHandle);
    	return 0;
    }
    执行结果:

    先显示 GetUp。等待3000ms后显示Breakfast,接着立即显示Work

    因为getupHandle和workHandle是设置为有信号的,它们的WaitForSingleObject直接有返回值

    breakfastHandle设置为无信号的,它的WaitForSingleObject必须等待回报的完成时间值

    版权声明:本文博主原创文章,博客,未经同意不得转载。

  • 相关阅读:
    创建用户自定义函数 SQL
    关于“该列没有包含在聚合函数或 GROUP BY 子句中”
    转Oracle性能参数—经典常用
    The server committed a protocol violation. Section=ResponseHeader Detail=CR must be followed by LF 错误
    js定时刷新
    用户获取mac地址的方法
    聚集索引和非聚集索引的区别
    WCF启动报错:“进程不具有此命名空间的访问权限”的解决方法
    利用js文件加载js文件的方法
    C#下载的几种方法
  • 原文地址:https://www.cnblogs.com/lcchuguo/p/4846039.html
Copyright © 2020-2023  润新知