【问题标题】:MsgWaitForMultipleObjects sometimes returns WAIT_FAILED with no GetLastError valueMsgWaitForMultipleObjects 有时会返回没有 GetLastError 值的 WAIT_FAILED
【发布时间】:2011-04-26 02:12:03
【问题描述】:

我有一个线程创建需要单线程单元的 COM 对象。

原来,这个线程的 main 函数把它放到了一个 WaitForMultipleObjects 循环中。显然这是一个问题,因为它阻止了 COM 消息泵的工作。

我将其替换为 MsgWaitForMultipleObjects 作为解决方案,但现在我遇到了一个问题:MsgWaitForMultipleObjects 有时(经常)返回 WAIT_FAILED,但没有设置错误。

代码通过继续并尝试再次调用 MsgWaitForMultipleObjects 来处理 WAIT_FAILED 返回值。对 MsgWaitForMultipleObjects 的调用可能会返回 WAIT_FAILED 几次(我见过的最多的是 9 次),但随后它突然可以正常工作了。

编写代码后,如果函数出于正当理由返回 WAIT_FAILED,则可能会进入无限循环。我知道我应该解决这个问题,但目前我认为这是一种“解决方法”,因为 MsgWaitForMultipleObjects 调用最终会成功。

此代码正在 Windows 7、Vista 和 XP(所有 32 位、Windows 7 32 和 64 位)上进行测试。

有人知道为什么会这样吗?

相关代码:

bool run = true;
while (run)
{
    DWORD ret = MsgWaitForMultipleObjects(2, events, FALSE, INFINITE, 
        QS_ALLINPUT);

    switch (ret)
    {
        case WAIT_OBJECT_0:
        {
            ResetEvent(events[0]);
            ProcessWorkQueue();
            break;
        }

        case WAIT_OBJECT_0 + 1:
        {
            run = false;
            break;
        }

        case WAIT_OBJECT_0 + 2:
        {
            MSG msg;
            while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
                DispatchMessage(&msg);
            break;
        }

        case WAIT_FAILED:
        {
            Logger::Output(L"Wait failed in Notify::Run(), error is " 
                + boost::lexical_cast<std::wstring>(GetLastError()));
        }
    }
}

示例输出为:

Wait failed in Notify::Run(), error is 0
Wait failed in Notify::Run(), error is 0
Wait failed in Notify::Run(), error is 0
Wait failed in Notify::Run(), error is 0
Wait failed in Notify::Run(), error is 0
Wait failed in Notify::Run(), error is 0
Wait failed in Notify::Run(), error is 0
Wait failed in Notify::Run(), error is 0
Wait failed in Notify::Run(), error is 0
// At this point, the wait succeeds

我相信 WAIT_FAILED 返回值仅在等待被消息中断后才会出现。

【问题讨论】:

  • 嗯,不知道是谁给了你使用 MsgWaitForMultipleObjects 的想法。好吧,希望他能访问这个帖子。

标签: c++ winapi com message-queue waitformultipleobjects


【解决方案1】:

这不应该发生,我也无法准确地解释为什么会发生。不过,我确实有一些建议。

首先,您不会在消息泵中调用TranslateMessage() 之前的DispatchMessage()。那是糟糕的juju,你不想在MsgWaitForMultipleObjects()附近有糟糕的juju。

您可能还想尝试显式调用MsgWaitForMultipleObjectsEx(),以防万一它没有出现同样的问题:

DWORD ret = MsgWaitForMultipleObjectsEx(2, events, INFINITE, QS_ALLINPUT, 0);

最后,这可能有点牵强,但请考虑在MsgWaitForMultipleObjects() 返回之后和GetLastError() 被调用之前发生的情况。忽略对ret 的分配,我看到对std::wstring 的构造函数的隐式调用。

你能保证std::wstring 的构造函数没有清除线程最后一个错误代码的副作用吗?我当然不能,所以我将对GetLastError() 的调用转移到DWORD 语句第一行中的DWORD 变量的良好、老式原子分配中。

【讨论】:

  • 感谢您的回复。我省略了TanslateMessage,因为它不应该处理任何关键消息,但我添加了它以防万一。 GetLastError 保证在构造 std::wstring 之前被调用,但无论如何我都预先存储了该值。两者都没有解决问题,但我会尝试使用 Ex 版本。
  • 抱歉,附带说明一下,我知道 GetLastError 没有被设置,因为我有时可以看到它的值表示“找不到文件”,我知道这是在哪里设置的.其他时候,它返回 0。
猜你喜欢
  • 2010-09-17
  • 1970-01-01
  • 2013-10-31
  • 1970-01-01
  • 1970-01-01
  • 2020-03-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多