多线程同步有很多方法,现在简单记录一下自己的程序对事件的使用。
包含的头文件
#include<Windows.h>
事件的使用步骤:(最简单的使用步骤)
1、定义一个句柄,用于事件的标识。
HANDLE aEvent;
2、创建事件(可以和第一个合并,注意对象的生存周期和作用范围):
aEvent = CreateEvent(NULL,FALSE,FALSE,NULL);
这样就创建了一个event,以后这个event就用aEvent标识。
3、等待事件被触发(这是最核心的地方,与第4步结合使用,用于多线程同步)。
WaitForSingleObject(aEvent ,3000);
意思就是当代码执行到这的时候,就会在此处阻塞着,直到另外一个线程里触发这个事件后(第4步)或者等待超时后,才会继续往下执行。
(此处的事件若是为NULL,那么程序会马上返回一个很大的DWORD (4294967295),程序继续往下执行,很容易造成程序里不可思议的错误。此处一定要小心)
#include<stdio.h>
#include<Windows.h>
void main()
{
HANDLE hMyEvent;
hMyEvent = CreateEvent(NULL,FALSE,FALSE,NULL);
//while (WaitForSingleObject(hMyEvent, 3000) != WAIT_OBJECT_0)
DWORD result = WaitForSingleObject(NULL, 3000);
while (result != WAIT_OBJECT_0)
{
printf("等待超时!!\n");
}
}
4、触发事件(与第三步结合使用,进行线程同步)。
SETEVENT(aEvent);
当线程里执行完这句代码之后,另外一个线程中阻塞等待该事件处(第三步)才会继续往下执行。
5、关闭句柄(当这个事件用完之后,要关闭句柄释放资源)。
CloseHandle(aEvent);
例子:(从业务中摘出的代码,只作例子,不能运行)
static unsigned int __stdcall GetPortThread(void* param);
uintptr_t g_GetPortTh = NULL;//获取串口号线程句柄
HANDLE g_GetPortEvent = NULL;//获取串口号事件
LONG g_TheGetPort = -1; // 获取到的设备所在串口号
g_GetPortEvent = CreateEvent(NULL , TRUE , FALSE , NULL);
main()
{
unsigned int nowBaudRate = 0;
//建立线程
g_GetPortTh = _beginthreadex(NULL,0,GetPortThread,NULL,0,NULL);
DWORD waitIndex = WaitForSingleObject(g_GetPortEvent,2000);
if ( WAIT_TIMEOUT == waitIndex )
{
return -1;
}
else
{
return g_TheGetPort;
}
}
unsigned int __stdcall CPatrolCtrlCtrl::GetPortThread(void* param)
{
unsigned int nowBaudRate = 0;
int i = 1;
for (;i<=16;i++)
{
if(SDT_GetCOMBaud(i,&nowBaudRate)==0x90)
{
g_TheGetPort = i;
SetEvent(g_GetPortEvent);//激活系统介素事件
return 0;
}
}
g_TheGetPort = -1;
return -1;
}
看完最简单的使用步骤后,就明白了事件到底是干什么的。但有时编程过程中会遇到很多复杂的情况,这就需要更复杂的使用方法。
主要有几点:
1、等待事件被触发函数有:
DWORD WaitForMultipleObjects(DWORD nCount, const HANDLE* lpHandles,BOOL bWaitAll,DWORD dwMilliseconds);
这个函数的参数:第一个是等待事件的个数,第二个是等待的事件的数组,第三个是等待事件全部被触发了才往下执行,还是只要有一个被触发了就往下执行,第四个是超时时间。
2、将事件设置为无信号状态(被触发之后重置)
ResetEvent();
在自动重置事件对象中,当WaitSingleObject/WaitForMultipleObjects接收到SetEvent发送过来的信号后则返回WAIT_OBJECT_0,此时操作系统(待定)自动重置等待的事件对象(即自动将其设置为无信号状态。无论何时通过SetEvent发送过来的信号,只要未被接收到均不会被自动重置。但在未被接收之前可以调用ResetEvent手动重置等待的事件对象,此时等待的事件对象为无信号状态)。在手动重置事件对象中,当WaitSingleObject/WaitForMultipleObjects接收到SetEvent发送过来的信号后则返回WAIT_OBJECT_0,此时需要调用ResetEvent手动重置等待的事件对象(即手动将其设置为无信号状态)。
3、BOOL bManualReset,BOOL bInitialState, LPTSTRlpName);
4、BOOL PulseEvent(HANDLE hEvent);
5、 HANDLE OpenEvent(DWORD dwDesiredAccess, BOOL bInheritHandle, LPCTSTRlpName);