关于MsgWaitForMultipleObjects函数是否有意义的问题(实在不懂故来请教)

九州剑王 2011-08-23 08:28:00
小弟有个困惑,我在主线程的定时函数里等待事件句柄,为了不导致页面消息阻塞,我写了MsgWaitForMultipleObjects函数,但是我在想,如果他可以放过那些页面消息的话,我的等待是否没有意义了,也就是说,事件还未被设置就被当做设置了?我只等待一个事件,MsgWaitForMultipleObjects(1,&TimeEvent.m_hObject,FALSE,INFINITE,QS_ALLEVENTS);就用了这么一句代码,请老兄们点拨一下,不胜感激涕零!
...全文
153 10 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
10 条回复
切换为时间正序
请发表友善的回复…
发表回复
蒋晟 2011-08-23
  • 打赏
  • 举报
回复
这个函数设计来就是为了防止界面阻塞的,你等到了消息之后要处理消息。不过这样另开消息循环的代码尽量少用,主消息循环可能有别的处理代码需要执行。你的这个示例可以做成异步的,另开线程等待。

这个函数我一般只在主窗口关闭前终止子线程用。
九州剑王 2011-08-23
  • 打赏
  • 举报
回复
[Quote=引用 7 楼 visualeleven 的回复:]

引用 4 楼 hfz8867879 的回复:
回复VisualEleven老兄:这我也想到可以判断是不是事件的响应,但是我想请问您,我是在定时器函数里等待,想做到的功能就是如果是事件激活了我就让定时器继续下一次执行,而不是的话,例如界面消息,我仍等待事件,并且不希望界面阻塞,不知道这样是否可以做得到呢

参看3#
[/Quote]
看到了,就是说,我应该把FALSE改成TRUE,仅剩下一个问题了,就是这么做会不会阻塞界面呢,我现在代码有点问题,暂时还测不了,所以来问下老兄结果。
我在DLL中定义的全局EVENT,想在用户程序中等待它,发现句柄是空的,所以想知道如何在DLL中导出来这个事件?是导地址还是导获取地址的函数?小弟才学了不到一个月,实在不清楚,希望您能指点下,让小弟以后就能触类旁通了...如何导出CEvent的全局变量
Eleven 2011-08-23
  • 打赏
  • 举报
回复
[Quote=引用 4 楼 hfz8867879 的回复:]
回复VisualEleven老兄:这我也想到可以判断是不是事件的响应,但是我想请问您,我是在定时器函数里等待,想做到的功能就是如果是事件激活了我就让定时器继续下一次执行,而不是的话,例如界面消息,我仍等待事件,并且不希望界面阻塞,不知道这样是否可以做得到呢
[/Quote]
参看3#
九州剑王 2011-08-23
  • 打赏
  • 举报
回复
chunyou128
(心如赤子)兄:您的代码和我的一样,所以我想问,如果我只想等待事件并且不造成截面线程阻塞,但是,这么写的话,截面线程来了也会完成等待了吧
我判断返回值是不是事件的设置后,该如何写函数呢?既可以接着等待事件,又不会阻塞截面线程。不知道我说清楚了没,小弟表达太差
chunyou128 2011-08-23
  • 打赏
  • 举报
回复
        // wait for any message sent or posted to this queue
// or for one of the passed handles to become signaled
dwWaitResult = MsgWaitForMultipleObjects(1, &vrghEvent[iThread],
FALSE, INFINITE, QS_ALLINPUT);
九州剑王 2011-08-23
  • 打赏
  • 举报
回复
回复VisualEleven老兄:这我也想到可以判断是不是事件的响应,但是我想请问您,我是在定时器函数里等待,想做到的功能就是如果是事件激活了我就让定时器继续下一次执行,而不是的话,例如界面消息,我仍等待事件,并且不希望界面阻塞,不知道这样是否可以做得到呢
Eleven 2011-08-23
  • 打赏
  • 举报
回复
DWORD MsgWaitForMultipleObjects(
DWORD nCount, //要等待的内核对象数目
LPHANDLE pHandles, //要等待的内核对象句柄数组指针
BOOL fWaitAll, //是等待全部对象还是单个对象
DWORD dwMilliseconds,//等待时间
DWORD dwWakeMask );//等待的消息类型

下面就详解一下该函数的参数使用方法:
DWORD nCount:要等待的内核对象的数目。如果等待两个线程退出,则nCount=2;
LPHANDLE pHandles:要等待的内核对象句柄数组指针。

如果只要等待一个线程退出,则直接设置该线程句柄的指针即可:
MsgWaitForMultipleObjects(1,&m_pThread->m_hThread,…)

如果要等待两个线程退出,则使用方法为:
HANDLE hArray[2]={ m_pThread1->m_hThread , m_pThread2->m_hThread };
MsgWaitForMultipleObjects(2,hArray,…)

BOOL fWaitAll: TRUE-表示只有要等待的线程全部退出后,此函数才返回,
FALSE-表示要等待的线程中任意一个退出了,或是有消息到达了,此函数均会返回。
在上面的OnButton2()函数中,我要等待一个线程退出,将fWaitAll设置为
FALSE,目的是无论是线程真的退出了,还是有消息到达了,该函数都能返回。
如果将该fWaitAll设置为TRUE,那么函数返回的唯一条件是线程退出了,即便
是有消息到来了,该函数也一样不会返回。

DWORD dwMilliseconds:等待的事件,单位是毫秒。可以设置为INFINITE,无
穷等待

DWORD dwWakeMask:等待的消息类型,通常可以设置为QS_ALLINPUT。此宏表示的是可以等待任意类型的消息。当然,也可以指定等待的消息类型。

#define QS_ALLINPUT (QS_INPUT | \
QS_POSTMESSAGE | \
QS_TIMER | \
QS_PAINT | \
QS_HOTKEY | \
QS_SENDMESSAGE)

返回值:DWORD dRet 通过函数返回值,可以得到一些有效信息。函数返回值依fWaitAll设置的不同而有所不同。下面是函数返回值的几种常见类型:

dRet = 0xFFFFFFFF : 表示函数调用失败,可用GetLastError()得到具体的出错信息;

dRet =WAIT_OBJECT_0+nCount:表示有消息到达了;



如果fWaitAll设置为TRUE

dRet = WAIT_OBJECT_0,表示所有等待的核心对象都激发了,或是线程都退出了;

如果fWaitAll设置为FALSE

dRet = WAIT_OBJECT_0 ~ WAIT_OBJECT_0+nCount-1:表示等待的内核对象被激发了,index=dRet - WAIT_OBJECT_0,表示hArray[]数组中索引为index的那个对象被激发了。



当函数由于消息到来而返回,则需要用户主动去消息队列中将消息抓取出来,然后派发出去,这样该消息就会被处理了。其具体的操作就是:

while (PeekMessage(&msg,NULL,0,0,PM_REMOVE))

{

TranslateMessage(&msg);

DispatchMessage(&msg);

}



下面再看一个用这个函数等待两个线程退出的例子:

//关闭线程1和2

void CThreadTest::OnButton6()

{





DWORD dRet=-2;

HANDLE hArray[2];



hArray[0]=m_pThread1->m_hThread;

hArray[1]=m_pThread2->m_hThread;



MSG msg;



int nExitThreadCount=0; //标记已经有几个线程退出了

BOOL bWaitAll=FALSE;

int nWaitCount=2; //初始等待的线程数目



while (1)

{

dRet=MsgWaitForMultipleObjects(nWaitCount,hArray,bWaitAll,INFINITE,QS_ALLINPUT);

if (dRet == WAIT_OBJECT_0+ nWaitCount)

{

TRACE("收到消息,函数返回值为%d \n",dRet);

while (PeekMessage(&msg,NULL,0,0,PM_REMOVE))

{

TranslateMessage(&msg);

DispatchMessage(&msg);

}



}

else if (dRet >= WAIT_OBJECT_0 && dRet < WAIT_OBJECT_0+ nWaitCount)

{

nExitThreadCount++;

if (nExitThreadCount == 1)

{

TRACE("一个线程退出了\n");

int nIndex=dRet-WAIT_OBJECT_0;

hArray[nIndex]=hArray[nWaitCount-1];

hArray[nWaitCount-1]=NULL;

nWaitCount--;



}

else

{

TRACE("两个线程都退出了\n");

break;

}

}

else

{

DWORD dErrCode=GetLastError();



break;

}

}



}



在上面这个例子中,我将bWaitAll设置为FALSE,目的是当我要等待的两个线程中由一个退出了,或是有消息到来了,此函数都可以退出。如果我将此参数设置为TRUE,那么,当且仅当我要等待的两个线程均退出了,这个函数才会返回,这种使用方法有是程序陷入死锁的危险,故应避免。无论是等待一个还是多个线程,只需将此参数设置为FALSE即可,然后通过函数返回值判断究竟是那个返回了,还是消息到达了即可。这一要点前面已有陈述,此处再强调一遍。

通过函数返回值可以得知究竟哪个线程退出了,当要等待的两个线程中的一个已经退出后,则应该从新设置等待函数的参数,对等待的句柄数组进行整理。

{

int nIndex=dRet-WAIT_OBJECT_0;

hArray[nIndex]=hArray[nWaitCount-1];

hArray[nWaitCount-1]=NULL;

nWaitCount--;

}

这组语句就是用来从新设置参数的,其过程就是将等待的总数目减一,并将刚退出的线程的句柄设置为NULL,移到数组的最末位置。

Eleven 2011-08-23
  • 打赏
  • 举报
回复
MsgWaitForMultipleObjects函数,该函数的特点是它不但可以等待内核对象,还可以等消息。也就是当有消息到来时,该函数也一样可以返回,并处理消息,这样就给了工作线程退出的机会。
Eleven 2011-08-23
  • 打赏
  • 举报
回复
判断MsgWaitForMultipleObjects函数的返回值~
九州剑王 2011-08-23
  • 打赏
  • 举报
回复
蒋老大都来了,不胜荣幸啊!收到了,我再试试看看新开线程!

16,548

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC相关问题讨论
社区管理员
  • 基础类社区
  • AIGC Browser
  • encoderlee
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

        VC/MFC社区版块或许是CSDN最“古老”的版块了,记忆之中,与CSDN的年龄几乎差不多。随着时间的推移,MFC技术渐渐的偏离了开发主流,若干年之后的今天,当我们面对着微软的这个经典之笔,内心充满着敬意,那些曾经的记忆,可以说代表着二十年前曾经的辉煌……
        向经典致敬,或许是老一代程序员内心里面难以释怀的感受。互联网大行其道的今天,我们期待着MFC技术能够恢复其曾经的辉煌,或许这个期待会永远成为一种“梦想”,或许一切皆有可能……
        我们希望这个版块可以很好的适配Web时代,期待更好的互联网技术能够使得MFC技术框架得以重现活力,……

试试用AI创作助手写篇文章吧