事件Event上是个内核对象,它的使用非常方便。下面列出一些常用的函数。
CreateEvent创建事件
/** \brief 创建事件
*
* \param lpEventAttributes 表示安全控制,一般直接传入NULL
* \param bManualReset 确定事件是手动置位还是自动置位,传入TRUE表示手动置位,传入FALSE表示自动置位。
* 如果为自动置位,则对该事件调用WaitForSingleObject()后会自动调用ResetEvent()使事件变成未触发状态。
* \param bInitialState 表示事件的初始状态,传入TRUR表示已触发
* \param lpName 表示事件的名称,是一个以0结束的字符串指针。名称的字符格式限定在MAX_PATH之内。
* 名字是对大小写敏感的。传入NULL表示匿名事件
* \return 成功,函数返回事件对象的句柄。如果对于命名的对象,在函数调用前已经被创建,函数将返回存在的事件对象的句柄,
* 而且在GetLastError函数中返回ERROR_ALREADY_EXISTS。
* 失败,函数返回值为NULL,如果需要获得详细的错误信息,需要调用GetLastError
*
*/
HANDLE CreateEvent(
LPSECURITY_ATTRIBUTES lpEventAttributes,
BOOL bManualReset,
BOOL bInitialState,
LPCTSTR lpName
);
其中HANDLE
是空指针类型。
OpenEvent返回事件对象的句柄
/** \brief 返回事件对象的句柄
*
* \param dwDesiredAccess 表示访问权限,对事件一般传入EVENT_ALL_ACCESS。
* \param bInheritHandle 事件句柄继承性。
* \param lpName 表示事件的名称,是一个以0结束的字符串指针。名称的字符格式限定在MAX_PATH之内。
* 名字是对大小写敏感的。
* \return 成功则返回事件对象的句柄;失败则返回NULL,获取错误信息可以使用GetLastError
*
*/
HANDLE OpenEvent(
DWORD dwDesiredAccess,
BOOL bInheritHandle,
LPCTSTR lpName
);
SetEvent触发事件
/** \brief 触发事件
* 每次触发后,必有一个或多个处于等待状态下的线程变成可调度状态
*
* \param hEvent 要触发的事件的句柄(内核对象)
* \return 成功,则返回非零值,否则为0。
*
*/
BOOL SetEvent(HANDLE hEvent);
ResetEvent将事件设为未触发
/** \brief 将事件设为未触发
*
* \param hEvent 指向事件对象的句柄,这个句柄需要拥有EVENT_MODIFY_STATE 访问权限
* \return 成功,返回非0值,否则返回0值,可以调用GetLastError得到错误的详细信息
*
*/
BOOL ResetEvent(HANDLE hEvent);
CloseHandle销毁
由于事件是内核对象,因此使用CloseHandle()就可以完成清理与销毁了。
/** \brief 关闭一个内核对象
*
* \param hObject 代表一个已打开对象handle。
* \return TRUE:执行成功;FALSE:执行失败,可以调用GetLastError()获知失败原因。
*
*/
BOOL CloseHandle(HANDLE hObject);
示例
主线程与2个子线程依次执行
#include <stdio.h>
#include <Windows.h>
#include <process.h>
void Thread1(void*);
void Thread2(void*);
volatile int count = 0;
HANDLE th1, th2;//线程句柄
unsigned long th1ID, th2ID;//线程ID
HANDLE e1, e2, e3;//事件句柄
int main()
{
/* 创建事件 */
//自动置位,初始化无触发的事件
e1 = CreateEvent(NULL, FALSE, FALSE, "e1");
e2 = CreateEvent(NULL, FALSE, FALSE, "e2");
e3 = CreateEvent(NULL, FALSE, FALSE, "e3");
/* 创建线程 */
th1 = _beginthread(Thread1, 0, NULL);
th2 = _beginthread(Thread2, 0, NULL);
/* 获取线程ID */
th1ID = GetThreadId(th1);
th2ID = GetThreadId(th2);
while (1)
{
Sleep(200);
printf("主线程\n");
SetEvent(e1);//触发事件1
WaitForSingleObject(e3, INFINITE);//等待事件3
}
/* 等待线程结束 */
WaitForSingleObject(th1, INFINITE);
/* 销毁事件 */
CloseHandle(e1);
CloseHandle(e2);
CloseHandle(e3);
return 0;
}
void Thread1(void* arg)
{
while (1)
{
WaitForSingleObject(e1, INFINITE);//等待事件1
//ResetEvent(e1);//如果事件是手动置位,则需要调用该函数给事件设置为未触发状态
count += 1;
printf("线程1 当前count的值为:%d\n", count);
SetEvent(e2, INFINITE);//触发事件2
}
}
void Thread2(void* arg)
{
while (1)
{
WaitForSingleObject(e2, INFINITE);//等待事件2
count += 50;
printf("线程2 当前count的值为:%d\n", count);
SetEvent(e3, INFINITE);//触发事件3
}
}
输出结果