当负责处理消息的线程挂起时会发生什么?

What happens when the thread that is responsible for processing messages is hung?

我有一个应用程序,其中一个 dll 模块负责处理用户定义的消息,这些消息被发布到它的隐藏 window。假设负责处理这些消息的线程在处理其他任务时挂起,并且在此期间,如果另一个低级别层将消息发布(使用 PostMessage)到此 window,将会发生什么发布的消息发生了什么?

我的应用程序有时收不到这些消息,低层的日志表明他们已经发布了消息,但我的应用程序没有收到。我怀疑由于线程正忙或挂起,它不会处理这些消息。我该如何解决这个问题?

简短的回答是,如果您使用隐藏的 window 来处理来自系统和其他应用程序组件的消息,那么保留该消息泵很重要 运行和处理消息。如果您有一个很长的 运行 任务,这将使您长时间远离消息队列,那么正确的答案是将该任务传递给一个单独的线程。

更复杂的答案是可能发生了两个问题:

  1. 消息队列已满。
  2. 未正确检查调用 PostMessage 的 return 值。

第一期很简单。 PostMessage 的文档非常清楚1:

There is a limit of 10,000 posted messages per message queue. This limit should be sufficiently large. If your application exceeds the limit, it should be redesigned to avoid consuming so many system resources.

要点是,消息处理中涉及的线程在获取下一条消息所需的行程之间应该尽可能少地执行操作,以保持应用程序的响应速度,并避免浪费资源。

您的代码中可能存在也可能不存在的第二个问题是需要检查 PostMessage 中的 return。文档详细说明了,但是 TL;DR;如果 return 值为 0,则调用失败。如果 且仅当 2 时 return 值为 0,调用 GetLastError 以获取错误代码。如果错误为 ERROR_NOT_ENOUGH_QUOTA,则队列已满。摘要形式:

if (PostMessage(hwnd, msg, wParam, lParam) == 0)
{
    if (GetLastError() == ERROR_NOT_ENOUGH_QUOTA)
    {
        cout << "Message Queue is Full" << endl;
    }
}

1 通常 MSDN 在说某事不应该做时并没有那么强硬。当某事如此明确时,最好听从建议。 (另外值得一提的是:增加配额是局部问题的全球解决方案。)

2 当一个函数成功时调用 GetLastError 是一个令人震惊的常见错误,或者当被调用的函数没有成功时 SetLastError.