首页 > 代码库 > CreateEvent、SetEvent、ResetEvent和WaitForSingleObject

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要等待定时完成才有返回值