Windows 内核对象(三) 事件内核对象
线程的执行顺序需求
有时候我们可能希望B线程等到A线程之后进行执行
我们看下面的例子
#include <Windows.h>
#include <process.h>
#include <tchar.h>
INT* g_pnNum;
BOOL g_bRuning = FALSE;
VOID Entry()
{
while (InterlockedExchange((LONG*)&g_bRuning, TRUE) == TRUE)
{
Sleep(0);
}
}
VOID Leave()
{
InterlockedExchange((LONG*)&g_bRuning, FALSE);
}
VOID ThreadPrint(TCHAR* szText)
{
Entry();
_tprintf(szText);
Leave();
}
UINT WINAPI StartThread(LPVOID lParam)
{
ThreadPrint(TEXT("StartThread is begin....\n"));
g_pnNum = new INT(0);
Sleep(1000);
ThreadPrint(TEXT("StartThread is end....\n"));
return 0;
}
UINT WINAPI EndThread(LPVOID lParam)
{
ThreadPrint(TEXT("EndThread is begin....\n"));
HANDLE hStart = (HANDLE)lParam;
ThreadPrint(TEXT("EndThread is waiting....\n"));
WaitForSingleObject(hStart, INFINITE);
ThreadPrint(TEXT("EndThread is end waiting....\n"));
delete g_pnNum;
ThreadPrint(TEXT("EndThread is end....\n"));
return 0;
}
INT _tmain()
{
HANDLE hStart = (HANDLE)_beginthreadex(NULL, 0, StartThread, NULL, 0, NULL);
HANDLE hEnd = (HANDLE)_beginthreadex(NULL, 0, EndThread, hStart, 0, NULL);
WaitForSingleObject(hEnd, INFINITE);
CloseHandle(hStart);
CloseHandle(hEnd);
return 0;
}- 我们写完代码之后, 会发现一个问题
- 我们不能保证我们的StartThread在我们的EndThread之前启动
- 对于强迫症来说, 这是一个瑕疵...
- 那么我们怎么来改呢?
- 我们使用
事件内核对象
事件内核对象
事件内核对象多用于来进行同步
它并没有代表系统中任何一个实体
它是为了编程人员使用方便而存在的
- 它可以
自动重置Signal状态 - 它可以
手动重置Signal状态 使用
CreateEvent/CreateEventEx(Vista系统之后)来创建一个事件内核对象bManualRest 用来规定如何重置事件内核对象
- TRUE 手动
- FALSE 自动
创建事件内核对象
CreateEvent
HANDLE WINAPI CreateEvent(
_In_opt_ LPSECURITY_ATTRIBUTES lpEventAttributes,
_In_ BOOL bManualReset,
_In_ BOOL bInitialState,
_In_opt_ LPCTSTR lpName
);lpEventAttributes
- 安全属性, 一般为NULL
bManualReset
- 是否手动重置
TRUE 手动重置
- 必须调用 ResetEvent 进行重置成无信号状态
- SetEvent 可以设置为有信号状态
- FALSE 系统自动重置
bInitialState
- 信号状态
- TRUE 是信号状态, 不会阻塞 Wait
- FALSE 是无信号状态, 会阻塞 Wait
lpName
- 事件内核对象的一个名称
- 在
打开事件内核对象的时候, 需要使用到名字 - 为了跨进程使用而设计
- 也可以为NULL, 表示只在本进程中使用
#include <Windows.h>
INT _tmain()
{
// 创建事件内核对象
HANDLE hEventManualRest = CreateEvent(NULL, TRUE, TRUE, TEXT("HadesEventManualRest"));
// 当前的事件内核对象是Signal状态, 所以下面的一句Wait不会阻塞
WaitForSingleObject(hEventManualRest, INFINITE);
// WaitForSingleObject会改变事件内核对象的信号状态
// 但是下面一句话并没有阻塞
// 因为我们的 事件内核对象 是手动更改信号状态
// 我们需要调用 ResetEvent 让Signal变为无信号
ResetEvent(hEventManualRest);
// 经过ResetEvent, 就会阻塞了
WaitForSingleObject(hEventManualRest, INFINITE);
CloseHandle(hEventManualRest);
// 创建事件内核对象
HANDLE hEventAutoRest = CreateEvent(NULL, TRUE, TRUE, TEXT("HadesEventAutoRest"));
// 当前的事件内核对象是Signal状态, 所以下面的一句Wait不会阻塞
WaitForSingleObject(hEventAutoRest, INFINITE);
// WaitForSingleObject会改变事件内核对象的信号状态
// 下面一句代码会阻塞
WaitForSingleObject(hEventManualRest, INFINITE);
CloseHandle(hEventAutoRest);
return 0;
}CreateEventEx
HANDLE WINAPI CreateEventEx(
_In_opt_ LPSECURITY_ATTRIBUTES lpEventAttributes,
_In_opt_ LPCTSTR lpName,
_In_ DWORD dwFlags,
_In_ DWORD dwDesiredAccess
);lpEventAttributes
- 安全属性
lpName
- 事件内核对象的名称
dwFlags
- 取自下面两个值, 或者它们的组合
- CREATE_EVENT_INITIAL_SET 有信号状态
CREATE_EVENT_MANUAL_RESET 手动设置信号状态
- 必须使用 ResetEvent 来设置无信号状态
- SetEvent 可以设置为有信号状态
- 如果
不指定该标志, 它将是自动信号的
dwDesiredAccess
- 事件内核对象的权限
- 它的取值范围取自同步对象安全和访问权限.aspx).
未完待续...
如有错误,请提出指正!谢谢.
本文由 花心胡萝卜 创作,采用 知识共享署名4.0 国际许可协议进行许可
本站文章除注明转载/出处外,均为本站原创或翻译,转载前请务必署名
最后编辑时间为: 2017-07-02 at 08:27 am