开发者

MsgWaitForMultipleObjects sometimes returns WAIT_FAILED with no GetLastError value

开发者 https://www.devze.com 2023-01-20 08:02 出处:网络
I have a thread that creates COM objects that require a single threaded apartment. Originally, this thread\'s main function put it i开发者_JAVA百科nto a WaitForMultipleObjects loop. Evidently this is

I have a thread that creates COM objects that require a single threaded apartment.

Originally, this thread's main function put it i开发者_JAVA百科nto a WaitForMultipleObjects loop. Evidently this is a problem, because it prevents the COM message pump from doing it's job.

I replaced this with MsgWaitForMultipleObjects as a solution, but now I'm running into an issue: MsgWaitForMultipleObjects sometimes (often) returns WAIT_FAILED, but doesn't set an error.

The code handles a WAIT_FAILED return value by just continuing and trying to call MsgWaitForMultipleObjects again. The call to MsgWaitForMultipleObjects may return WAIT_FAILED a few times (the most I've seen is 9), but then it suddenly works with no problem.

The code is written so that this could potentially go into an infinite loop if the function were returning WAIT_FAILED for a valid reason. I know I should fix this, but at the moment I'm considering it a 'work around' because the MsgWaitForMultipleObjects call will eventually succeed.

This code is being tested on Windows 7, Vista, and XP (all 32-bit, Windows 7 32- and 64-bit).

Does anyone have any idea why this is happening?

The relevant code:

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()));
        }
    }
}

Example output would be:

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

I believe the WAIT_FAILED return value is only occurring after the wait has been broken by a message.


That shouldn't be happening, and I sure can't explain exactly why it does. I do have a few pointers, however.

First, you're not calling TranslateMessage() before DispatchMessage() in your message pump. That's bad juju, and you don't want bad juju anywhere near MsgWaitForMultipleObjects().

You also might want to try explicitly calling MsgWaitForMultipleObjectsEx(), just in case it doesn't exhibit the same problem:

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

Finally, it might be far-fetched but consider what's happening after MsgWaitForMultipleObjects() returns and before GetLastError() is called. Disregarding the assignment to ret, I see an implicit call to std::wstring's constructor.

Can you guarantee std::wstring's constructor doesn't have some side-effect that clears the thread's last error code? I sure can't, so I'd move the call to GetLastError() into an good, old-fashioned, atomic assignment to a DWORD variable in the first line of the case statement.

0

精彩评论

暂无评论...
验证码 换一张
取 消