01、目录
02、函数介绍
MsgWaitForMultipleObjects
功能:阻塞时仍可以响应消息,“对象被激发”或“消息到达队列”时被唤醒而返回
相关API:WaitForMultipleObjects(),此API接收到消息后不会被唤醒和返回。
MsgWaitForMultipleObjects()多接收一个参数,允许指定哪些消息是观察对象。
2.1 函数创建
DWORD MsgWaitForMultipleObjects(
DWORD nCount,
LPHANDLE pHandles,
BOOL fWaitAll,
DWORD dwMilliseconds,
DWORD dwWakeMask
);
参数说明:
- DWORD nCount:表示pHandles所指的handles数组的元素个数,最大容量是MAXIMUM_WAIT_OBJECTS
- LPHANDLE pHandles:指向一个由对象handles组成的数组,这些handles的类型不需要相同
- BOOL fWaitAll:是否等待所有的handles被激发才返回
- DWORD dwMilliseconds:超时时间
- DWORD dwWakeMask:欲观察的用户输入消息类型
2.2 函数返回值
- WAIT_TIMEOUT :因时间终了而返回(等待超时)
- WAIT_OBJECT_0 :当bWaitAll是TRUE
- WAIT_OBJECT_0 to (WAIT_OBJECT_0 + nCount – 1) :bWaitAll是FALSE,将返回值减去WAIT_OBJECT_0,就表示数组中哪一个handle被激发了
- WAIT_ABANDONED_0 to (WAIT_ABANDONED_0 + nCount – 1) :等待的对象中有任何mutexes
- WAIT_FAILED :函数失败时返回该值,可以使用GetLastError()找出失败的原因
- WAIT_OBJECT_0 + nCount :消息到达队列
2.3 函数使用事项
MsgWaitForMultipleObjects()的正确使用方式是改写主消息循环,
使得激发状态的handles得以像消息一样被对待。
通常程序中只会有一个地方调用MsgWaitForMultipleObjects(),而这个调用存在于消息循环中。
PS:
- 在收到WM_QUIT之后,Windows仍然会传送消息给你,如果要在收到WM_QUIT之后等待所有线程结束,必须继续处理你的消息,否则窗口会变得反应迟钝,而且没有重绘能力。
- MsgWaitForMultipleObjects()不允许handles数组中有缝隙产生。所以当某个handle被激发了时,应该在下一次调用MsgWaitForMultipleObjects之前先把handles数组做个整理、紧压,不要只是把数组中的handle设为NULL。
- 如果有另一个线程改变了对象数组,而那是你正在等待的,那么需要一种方法,可以强迫MsgWaitForMultipleObjects返回,并重新开始,以包含新的handle。
03、示例
此实例为网上找的,实际意义自行理解,这里不便多揣测,以免理解有误,误导各位。
void WaitForThreadExit(void)
{
DWORD dwRet; //返回值
MSG msg;
int wait_count=4; //线程句柄有4个
int nExitThreadCount=0; //记录线程退出个数
while(1)
{
dwRet = MsgWaitForMultipleObjects(wait_count, hArray, FALSE, INFINITE, QS_ALLINPUT); //等待时间和消息,不阻塞消息
if (dwRet == WAIT_OBJECT_0 + wait_count)
{
//消息到达队列,需要对消息进行重判断防止意外退出或卡死
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))//获取队列消息 PM_REMOVE -PeekMessage处理后,消息从队列里除掉。
{
if (msg.message==WM_QUIT||msg.message==WM_CLOSE)
{
break;
}
TranslateMessage(&msg); //将虚拟键消息转换为字符消息
DispatchMessage(&msg); //发一个消息给窗口程序
}
}
else if (dwRet >= WAIT_OBJECT_0 && dwRet < WAIT_OBJECT_0+ wait_count)
{
//线程组中返回消息
nExitThreadCount++;
if (nExitThreadCount < 4)
{
//将等待数组句柄移位,使得连续句柄之间没有null。
TRACE("一个线程退出了\n");
int nIndex=dwRet-WAIT_OBJECT_0;
hArray[nIndex]=hArray[wait_count-1];
hArray[wait_count-1]=NULL;
wait_count--;
}
else
{
TRACE("4个线程都退出了\n");
break;
}
}
else
{
//错误退出
DWORD dErrCode=GetLastError();
break;
}
}
}
04、小结
小结之前,这里介绍一下Linue 与 Windows两个平台C++中线程的API对比表,如下:
OK,此文结束!
版权声明:转载请注明出处,谢谢!