我有一个线程创建需要单线程单元的 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 返回值仅在等待被消息中断后才会发生。

有帮助吗?

解决方案

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

首先,你没有打电话 TranslateMessage()DispatchMessage() 在你的消息泵中。那是糟糕的juju,你不希望附近有糟糕的juju MsgWaitForMultipleObjects().

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

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

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

你能保证 std::wstring的构造函数没有清除线程最后一个错误代码的副作用吗?我当然不能,所以我会将电话转至 GetLastError() 变成一个好的、老式的、原子的赋值给 DWORD 第一行的变量 case 陈述。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top