Win32 CreateEvent 事件对象
  3cAxQ5E22S4z 2023年11月15日 18 0

储备知识

事件对象就像一个开关:它只有两种状态---开和关。当一个事件处于”开”状态,我们称其为”有信号”否则称为”无信号”。可以在一个线程的执行函数中创建一个事件对象,然后观察它的状态,如果是”无信号”就让该线程睡眠,这样该线程占用的CPU时间就比较少。

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

HANDLE CreateEvent(

LPSECURITY_ATTRIBUTES lpEventAttributes, // SD
BOOL bManualReset, // reset type
BOOL bInitialState, // initial state
LPCTSTR lpName // object name
);
该函数创建一个Event同步对象,如果CreateEvent调用成功的话,会返回新生成的对象的句柄,否则返回NULL。

参数说明:
lpEventAttributes 一般为NULL

bManualReset 创建的Event是自动复位还是人工复位.如果true,人工复位, 一旦该Event被设置为有信号,则它一直会等到ResetEvent()API被调用时才会恢复 为无信号. 如果为false,Event被设置为有信号,则当有一个wait到它的Thread时, 该Event就会自动复位,变成无信号. 如果想 在每次调用WaitForSingleObject 后让WINDOWS为您自动地把事件地状态恢复为”无信号”状态,必须把该参数设为FALSE,否则,您必须每次调用ResetEvent函数来清除事件 的信号。

bInitialState 初始状态,true,有信号,false无信号
lpName 事件对象的名称。您在OpenEvent函数中可能使用。

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

PulseEvent()是一个比较有意思的使用方法,正如这个API的名字,它使一个Event 对象的状态发生一次脉冲变化,从无信号变成有信号再变成无信号,而整个操作是原子的.
对自动复位的Event对象,它仅释放第一个等到该事件的thread(如果有),而对于人工复位的Event对象,它释放所有等待的thread.

这里有两个API函数用来修改事件对象的信号状态:SetEvent和ResetEvent。前者把事件对象设为”有信号”状态,而后者正好相反。
在事件对象生成后,必须调用WaitForSingleObject来让线程进入等待状态,该函数的语法如下:

WaitForSingleObject proto hObject:DWORD, dwTimeout:DWORD

hObject -->指向同步对象的指针。事件对象其实是同步对象的一种。
dwTimeout --> 等待同步对象变成”有信号”前等待的时间,以毫秒计。当等待的时间超过该值后无信号同步对象仍处于”无信号”状态,线程不再等待, WaitForSingleObject函数会返回。如果想要线程一直等待,请把该参数设为INFINITE(该值等于0xffffffff)。

实例代码

1 创建事件信号,并且处于有信号的状态

启动的线程检测到有信号,WaitForSingleObject函数立刻返回WAIT_OBJECT_0

#include <iostream>
#include <windows.h>
using namespace std;

DWORD WINAPI ThreadProc1(LPVOID lpParam);
DWORD WINAPI ThreadProc2(LPVOID lpParam);
HANDLE hEvent = NULL;
HANDLE hThread1 = NULL;
HANDLE hThread2 = NULL;
int main(int argc, char *args[])
{
	hEvent = CreateEvent(NULL, TRUE, TRUE, NULL); //初始化时有信号状态
	hThread1 = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)ThreadProc1, NULL, 0, NULL);
	hThread2 = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)ThreadProc2, NULL, 0, NULL);
	if (NULL == hThread1)
	{
		std::cout << "创建线程1失败" << std::endl;
	}
	::system("pause");
	return 0;
}
DWORD WINAPI ThreadProc1(LPVOID lpParam)
{
	std::cout << "成功启动线程1" << std::endl;
	DWORD dReturn = WaitForSingleObject(hEvent, INFINITE);
	if (WAIT_OBJECT_0 == dReturn)
	{
		std::cout << "线程1检测到有信号" << std::endl;
	}
	return 0;
}
DWORD WINAPI ThreadProc2(LPVOID lpParam)
{
	std::cout << "成功启动线程2" << std::endl;
	DWORD dReturn = WaitForSingleObject(hEvent, INFINITE);
	if (WAIT_OBJECT_0 == dReturn)
	{
		std::cout << "线程2检测到有信号" << std::endl;
	}
	return 0;
}

2创建事件信号,并且处于无信号的状态

主线程等线程启动,12秒以后手动触发信号状态,WaitForSingleObject函数立刻返回WAIT_OBJECT_0

#include <iostream>
#include <windows.h>
using namespace std;

DWORD WINAPI ThreadProc1(LPVOID lpParam);
DWORD WINAPI ThreadProc2(LPVOID lpParam);
HANDLE hEvent = NULL;
HANDLE hThread1 = NULL;
HANDLE hThread2 = NULL;
int main(int argc, char *args[])
{
	hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); //初始化时有信号状态
	hThread1 = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)ThreadProc1, NULL, 0, NULL);
	hThread2 = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)ThreadProc2, NULL, 0, NULL);
 	Sleep(12000);
	std::cout << "手动触发信号" << std::endl;
 	::SetEvent(hEvent);
	if (NULL == hThread1)
	{
		std::cout << "创建线程1失败" << std::endl;
	}
	::system("pause");
	return 0;
}
DWORD WINAPI ThreadProc1(LPVOID lpParam)
{
	std::cout << "成功启动线程1" << std::endl;
	DWORD dReturn = WaitForSingleObject(hEvent, INFINITE);
	if (WAIT_OBJECT_0 == dReturn)
	{
		std::cout << "线程1检测到有信号" << std::endl;
	}
	return 0;
}
DWORD WINAPI ThreadProc2(LPVOID lpParam)
{
	std::cout << "成功启动线程2" << std::endl;
	DWORD dReturn = WaitForSingleObject(hEvent, INFINITE);
	if (WAIT_OBJECT_0 == dReturn)
	{
		std::cout << "线程2检测到有信号" << std::endl;
	}
	return 0;
}

注意

1 不在创建窗口和有消息循环的线程或者主线程,调用WaitForSingleObject,导致死锁

2 关闭事件对象的时候,先退出WaitForSingleObject的等待,避免出现未可知的情况

【版权声明】本文内容来自摩杜云社区用户原创、第三方投稿、转载,内容版权归原作者所有。本网站的目的在于传递更多信息,不拥有版权,亦不承担相应法律责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@moduyun.com

  1. 分享:
最后一次编辑于 2023年11月15日 0

暂无评论

3cAxQ5E22S4z