MsgWaitForMultipleObjects 后遗症 与解决办法

来源:互联网 发布:tensorflow 自己的算法 编辑:程序博客网 时间:2024/04/28 01:38

调用SendMessage 产生死锁的问题分析 之后,我在界面程序中不再使用 WaitForSingleObject 了,而改用如下的函数

DWORD WaitObjectAndMsg(HANDLE hEventThread, DWORD dwMilliseconds){BOOL bWait = TRUE;DWORD dwEvt = 0;while(bWait) {DWORD dwEvt = ::MsgWaitForMultipleObjects(1 , &hEventThread, FALSE, dwMilliseconds, QS_ALLINPUT);switch (dwEvt) {case WAIT_OBJECT_0: {return WAIT_OBJECT_0;}break;case WAIT_OBJECT_0 + 1: {MSG msg;while ( ::PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE)) {if( WM_CLOSE == msg.message || WM_QUIT == msg.message ) {return WAIT_FAILED;break;} else {PeekMessage(&msg, NULL, 0, 0, PM_REMOVE);::TranslateMessage(&msg); ::DispatchMessage(&msg); }} break;} default: {return dwEvt;break;} } }return dwEvt;}



这个函数看起来不错,在等待一个 Object 的同时,还可以边等待,边处理消息
今天才发现,这样处理有缺陷

如果在等待一个Object 时,哪怕只有 0.00001 秒,这里如果一个不小心处理了消息

那么 很自然会走到这个语句 ::DispatchMessage(&msg);

经过调试发现, ::DispatchMessage(&msg); 是阻塞的,

如果在处理消息的函数里,调用了一个

CDialog dlg;
dlg.DoModal(); 这里也是阻塞的, 如果这个窗口一直不关闭,

即使这时候 Object 已经响应了,但这个函数仍然不返回,,,,,,,因为它在双重的消息处理中。。。。。。。

下面是可参考解决办法

One danger oftheMsgWaitForMultipleObjects functionis calling it when there are already messages waiting to be processed, becauseMsgWaitForMultipleObjectsreturns only when there is a new event in the queue.

In other words, consider the following scenario:

  • PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE) returns TRUE indicating that there is a message.
  • Instead of processing the message, you ignore it and call MsgWaitForMultipleObjects.

This wait will not return immediately, even though there is a message in the queue. That's because the call toPeekMessage told you that a message was ready, and you willfully ignored it. TheMsgWaitForMultipleObjects message tells you only when there are new messages; any message that you already knew about doesn't count.

A common variation on this is the following:

  • MsgWaitForMultipleObjects returns that there is a message.
  • You call PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) and process that message.
  • You call MsgWaitForMultipleObjects to wait for more messages.

If it so happens that there were two messages in your queue, theMsgWaitForMultipleObjects does not return immediately, because there are no new messages; there is an old message you willfully ignored, however.

When MsgWaitForMultipleObjects tells you that there is a message in your message queue, you have to processallof the messages untilPeekMessage returnsFALSE, indicating that there are no more messages.

Note, however, that this sequence is not a problem:

  • PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE) returns FALSE indicating that there is no message.
  • A message is posted into your queue.
  • You call MsgWaitForMultipleObjects and include the QS_ALLPOSTMESSAGE flag.

This wait does return immediately, because the incoming posted message sets the "There is a new message in the queue that nobody knows about" flag, whichQS_ALLPOSTMESSAGE matches and therefore causesMsgWaitForMultipleObjects to return immediately.

TheMsgWaitForMultipleObjectsEx functionlets you pass theMWMO_INPUTAVAILABLE flag to indicate that it should check for previously-ignored input.

Armed with this knowledge, explain why the observed behavior with the following code is "Sometimes my program gets stuck and reports one fewer record than it should. I have to jiggle the mouse to get the value to update. After a while longer, it falls two behind, then three..."

// Assume that there is a worker thread that processes records and// posts a WM_NEWRECORD message for each new record.BOOL WaitForNRecords(HANDLE h, UINT cRecordsExpected){  MSG msg;  UINT cRecords = 0;  while (true) {    switch (MsgWaitForMultipleObjects(1, &h,                         FALSE, INFINITE, QS_ALLINPUT)) {    case WAIT_OBJECT_0:      DoSomethingWith(h); // event has been signalled      break;    case WAIT_OBJECT_1:      // we have a message - peek and dispatch it      if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {        TranslateMessage(&msg);        DispatchMessage(&msg);      }      if (SendMessage(hwndNotify, WM_GETRECORDCOUNT,                      0, 0) >= cRecordsExpected) {        return TRUE; // we got enough records      }      break;    default:      return FALSE; // unexpected failure    }  }}


 

原创粉丝点击