我有一个线程可以创建需要单线程单元的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返回值仅在等待被消息中断后才会发生。
答案 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
变量的一个好的,老式的原子赋值中。