引言
在window c++编程中,为了等待线程结束或者同步对象有限号,我们常常使用WaitForSingleObject
API函数,从字面上就可以看出,该接口是用于等待单个对象。而实际编码中,我们会遇到需要等待多个对象同时符合条件或者多个对象中的一个符合条件就执行某个事件,而本文讨论的WaitForMultipleObjects
API就可以满足同时监控多个对象的需求。为了对比它们的差异点,下面分别给出接口参数。
WaitForSingleObject 接口:
DWORD WaitForSingleObject(
HANDLE hHandle, /*等待对象的句柄*/
DWORD dwMilliseconds /*等待事件*/
);
WaitForMultipleObjects 接口:
DWORD WaitForMultipleObjects(
DWORD nCount, /*监控对象的个数*/
const HANDLE *lpHandles, /*一组对象句柄的指针*/
BOOL bWaitAll, /*是否等待全部符合条件*/
DWORD dwMilliseconds /*等待事件*/
);
异同点说明
从上面就可以看出,这个两个的接口参数不同点,这里主要说明下他们的返回值和监控的对象异同点。
返回值差异点:
WaitForSingleObject 返回值:
- WAIT_OBJECT_0 监控对象有信号
- WAIT_TIMEOUT 规定时间内未返回或者有信号
- WAIT_FAILED 等待是失败,具体情况见查看msdn
WaitForMultipleObjects 返回值:
WaitForMultipleObjects 返回值比WaitForSingleObject 多一个WAIT_ABANDONED_0
,这个不在此次讨论范围内。
当bWaitAll为TRUE时,它们的返回值是是一样的分别是WAIT_OBJECT_0
, WAIT_TIMEOUT
,WAIT_FAILED
.
当bWaitAll为FALSE时,并且没有失败或者超时情况下,它可以监控到是哪一个对象有信号或者线程返回。其返回值访问从WAIT_OBJECT_0
到WAIT_OBJECT_0 + nCount - 1
。
当只有一个对象返回时,其返回值 - WAIT_OBJECT_0
就是句柄数组的索引。
WAIT_OBJECT_0 + 0 代表句柄数组中的第0个对象
WAIT_OBJECT_0 + 1 代表句柄数组中的第1个对象
...
WAIT_OBJECT_0 + nCount -1 代表句柄数组中的最后一个对象
当规定时间内,有多个对象有信号或者线程返回,其返回值的其中最小的一个。
监控对象
都会监控的对象列表:
- Event
- Mutex
- Process
- Semaphore
- Thread
WaitForMultipleObjects 新增的监控列表:
- Change notification
- Console input
- Memory resource notification
- Waitable timer
示例代码
以下代码可以直接在vs编译器中执行,大家可以更加不同的参数进行测试和验证。
#include "stdafx.h"
#include <windows.h>
#include <stdio.h>
#include <process.h>
unsigned __stdcall SetMyEvent(void *lpParam)
{
if (NULL != lpParam)
{
HANDLE* hEvent = (HANDLE*)lpParam;
Sleep(2000);
::SetEvent(*hEvent);
}
return 0;
}
unsigned __stdcall SleepThread(void *pSleeptime)
{
if (NULL != pSleeptime)
{
int Sleeptime = (*(int*)pSleeptime) ;
Sleep(Sleeptime * 1000);
}
return 0;
}
int _tmain(int argc, _TCHAR* argv[])
{
const int EVENT_NUM = 2;
HANDLE hObject[EVENT_NUM] = {NULL,NULL};
//创建线程,2秒后hObject[0]事件对象变成有信号
hObject[0] = ::CreateEvent(NULL,FALSE,FALSE,NULL);
HANDLE hThread = (HANDLE)_beginthreadex(NULL,0,SetMyEvent,(void*)&hObject[0],0,NULL);
CloseHandle(hThread); //后续不会对该线程进行操作,直接关掉句柄
//创建线程,并等待线程结束
int nSleepTime = 1;
hObject[1] = (HANDLE) _beginthreadex(NULL,0,SleepThread,(void*)&nSleepTime,0,NULL);
//等待事件对象有信号、线程返回
DWORD dwEvent = WaitForMultipleObjects(EVENT_NUM, hObject, FALSE/*TRUE*/, 1500);
switch(dwEvent)
{
case WAIT_OBJECT_0 + 0: /*hObject[0]有信号*/
{
printf("event arrived ...\n");
/*TODO 自定义特殊处理*/
break;
}
case WAIT_OBJECT_0 + 1: /*hObject[1]线程返回*/
{
printf("thread return ...\n");
/*TODO 自定义特殊处理*/
break;
}
case WAIT_TIMEOUT: /*规定时间内,定义的事件和线程均未返回或者有信号*/
{
printf("wait multi object timeout ...\n");
/*TODO 自定义特殊处理*/
break;
}
default:
{
printf("wait for multi object error...\n");
}
}
for (int i = 0; i < EVENT_NUM; i++)
{
CloseHandle(hObject[i]);
}
return 0;
}
更多资料可参见MSDN
https://docs.microsoft.com/zh-cn/windows/win32/sync/waiting-for-multiple-objects