MsgWaitForMultipleObjects有时返回WAIT_FAILED而没有GetLastError值

时间:2010-10-15 18:25:31

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

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

最初,这个线程的主函数将它放入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返回值仅在等待被消息中断后才会发生。

1 个答案:

答案 0 :(得分:2)

这不应该发生,我肯定无法解释为什么。不过,我确实有一些指示。

首先,您没有在消息泵中TranslateMessage()之前致电DispatchMessage()。这是糟糕的juju,你不希望在MsgWaitForMultipleObjects()附近的任何地方出现坏juju。

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

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

最后,它可能是牵强附会,但要考虑在MsgWaitForMultipleObjects()返回之后和调用GetLastError()之前发生了什么。无视ret的作业,我看到对std::wstring的构造函数的隐式调用。

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