WaitForSingleObject
当进程正在运行的时候,进程内核对象处于未通知状态,当进程终止运行的时候,它就变
为已通知状态。进程内核对象中是个布尔值,当对象创建时,该值被初始化为FALSE(未通知
状态)。当进程终止运行时,操作系统自动将对应的对象布尔值改为TRUE,表示该对象已经得
到通知。
等待函数可使线程自愿进入等待状态,直到一个特定的内核对象变为已通知状态为止。
DWORD
WaitForSingleObject (HANDLE hObject, DWORD dwMilliseconds);
当线程调用该函数时,第一个参数hObject标识一个能够支持被通知/未通知的内核对象
(前面列出的任何一种对象都适用)。第二个参数dwMilliseconds允许该线程指明,为了等待该
对象变为已通知状态,它将等待多长时间。
调用下面这个函数将告诉系统,调用函数准备等待到hProcess句柄标识的进程终止运行为止:
WaitForSingleObject(
hProcess, INFINITE
);
第二个参数告诉系统,调用线程愿意永远等待下去(无限时间量),直到该进程终止运行。
通常情况下,INFINITE是作为第二个参数传递给WaitForSingeObject 也可以传递
任何一个值(以毫秒计算)。顺便说一下, INFINITE已经定义为0xFFFFFFFF(或-1)。当然,
传递INFINITE有些危险。如果对象永远不变为已通知状态,那么调用线程永远不会被唤醒,
它将永远处于死锁状态,不过,它不会浪费宝贵的CPU时间。
WaitForSingleObject函数用来检测hHandle事件的信号状态,在某一线程中调用该函数时,线程暂时挂起,如果在挂起的dwMilliseconds毫秒内,线程所等待的对象变为有信号状态,则该函数立即返回;如果超时时间已经到达dwMilliseconds毫秒,但hHandle所指向的对象还没有变成有信号状态,函数照样返回。参数dwMilliseconds有两个具有特殊意义的值:0和INFINITE。若为0,则该函数立即返回;
若为INFINITE,则线程一直被挂起,直到hHandle所指向的对象变为有信号状态时为止。
WAIT_ABANDONED 0x00000080:当hHandle为mutex时,如果拥有mutex的线程在结束时没有释放核心对象会引发此返回值。
WAIT_OBJECT_0 0x00000000 :指定的对象出有有信号状态
WAIT_TIMEOUT 0x00000102:等待超时
WAIT_FAILED 0xFFFFFFFF :出现错误,可通过GetLastError得到错误代码
#include "..\CommonFiles\CmnHdr.h" /* See Appendix A. */
#include <windowsx.h>
#include <tchar.h>
#include "Resource.h"
///
// 提交事件对象
HANDLE g_hevtRequestSubmitted;
// 返回事件对象
HANDLE g_hevtResultReturned;
// 共享缓存区
TCHAR g_szSharedRequestAndResultBuffer[1024];
// 特殊字符内容
TCHAR g_szServerShutdown[] = TEXT("Server Shutdown");
// 全局窗口句柄
HWND g_hMainDlg;
///
DWORD WINAPI ServerThread(PVOID pvParam) {
// 循环等待标志位
BOOL fShutdown = FALSE;
while (!fShutdown) {
// 等待提交事件对象为通知状态
WaitForSingleObject(g_hevtRequestSubmitted, INFINITE);
// 判断窗口是否关闭和是否提交了特殊字符,有则准备停止服务线程
fShutdown =
(g_hMainDlg == NULL) &&
(_tcscmp(g_szSharedRequestAndResultBuffer, g_szServerShutdown) == 0);
if (!fShutdown) {
// 反转共享缓存区数据内容
_tcsrev(g_szSharedRequestAndResultBuffer);
}
// 服务线程处理好,将返回事件设置通知状态
SetEvent(g_hevtResultReturned);
}
return(0);
}
///
// 初始化
BOOL Dlg_OnInitDialog(HWND hwnd, HWND hwndFocus, LPARAM lParam) {
chSETDLGICONS(hwnd, IDI_HANDSHAKE);
Edit_SetText(GetDlgItem(hwnd, IDC_REQUEST), TEXT("Some test data"));
g_hMainDlg = hwnd;
return(TRUE);
}
///
// 窗体事件处理
void Dlg_OnCommand(HWND hwnd, int id, HWND hwndCtl, UINT codeNotify) {
switch (id) {
case IDCANCEL:
EndDialog(hwnd, id);
break;
case IDC_SUBMIT: // 提交事件
// 获取输入的数据,保存到共享缓存区
Edit_GetText(GetDlgItem(hwnd, IDC_REQUEST),
g_szSharedRequestAndResultBuffer,
_countof(g_szSharedRequestAndResultBuffer));
// 将提交的事件对象设置为通知状态等待返回的事件对象
SignalObjectAndWait(g_hevtRequestSubmitted, g_hevtResultReturned, INFINITE, false);
// 服务线程处理好,显示到界面
Edit_SetText(GetDlgItem(hwnd, IDC_RESULT),
g_szSharedRequestAndResultBuffer);
break;
}
}
///
// 消息回调函数
INT_PTR WINAPI Dlg_Proc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
switch (uMsg) {
chHANDLE_DLGMSG(hwnd, WM_INITDIALOG, Dlg_OnInitDialog);
chHANDLE_DLGMSG(hwnd, WM_COMMAND, Dlg_OnCommand);
}
return(FALSE);
}
///
// 主线程
int WINAPI _tWinMain(HINSTANCE hInstanceExe, HINSTANCE, PTSTR, int) {
// 创建2个未通知的自动重置事件对象
g_hevtRequestSubmitted = CreateEvent(NULL, FALSE, FALSE, NULL);
g_hevtResultReturned = CreateEvent(NULL, FALSE, FALSE, NULL);
// 启动服务线程
DWORD dwThreadID;
HANDLE hThreadServer = chBEGINTHREADEX(NULL, 0, ServerThread, NULL,
0, &dwThreadID);
// 进入Dlg_Proc回调函数,当窗口关闭退出DialogBox
DialogBox(hInstanceExe, MAKEINTRESOURCE(IDD_HANDSHAKE), NULL, Dlg_Proc);
g_hMainDlg = NULL;
// 拷贝特殊的字符进入共享缓存区
_tcscpy_s(g_szSharedRequestAndResultBuffer,
_countof(g_szSharedRequestAndResultBuffer), g_szServerShutdown);
// 将提交事件设置通知状态,服务线程被唤醒
SetEvent(g_hevtRequestSubmitted);
// 等待服务线程设置的事件状态和线程状态
HANDLE h[2];
h[0] = g_hevtResultReturned;
h[1] = hThreadServer;
WaitForMultipleObjects(2, h, TRUE, INFINITE);
// 服务线程退出则退出等待,开始销毁内核对象
CloseHandle(hThreadServer);
CloseHandle(g_hevtRequestSubmitted);
CloseHandle(g_hevtResultReturned);
return(0);
}