1

シングル スレッド アパートメントを必要とする COM オブジェクトを作成するスレッドがあります。

もともと、このスレッドのメイン関数は、WaitForMultipleObjects ループに入れていました。COM メッセージ ポンプが本来の役割を果たせなくなるため、これは明らかに問題です。

解決策としてこれを MsgWaitForMultipleObjects に置き換えましたが、現在問題が発生しています。

このコードは、処理を続行して 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 の戻り値は、メッセージによって待機が中断された後にのみ発生していると思います。

4

1 に答える 1

2

それは起こってはならないことであり、なぜそうなるのかを正確に説明することはできません。しかし、私にはいくつかの指針があります。

まず、メッセージポンプでTranslateMessage()以前に電話をかけていません。DispatchMessage()それは悪いジュジュです、そしてあなたは近くのどこにも悪いジュジュを望んでいませんMsgWaitForMultipleObjects()

MsgWaitForMultipleObjectsEx()同じ問題が発生しない場合に備えて、明示的に呼び出してみることもできます。

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

最後に、それはとてつもないものかもしれませんが、MsgWaitForMultipleObjects()戻った後、GetLastError()呼び出される前に何が起こっているかを考えてみてください。への割り当てを無視すると、のコンストラクターretへの暗黙の呼び出しが表示されます。std::wstring

std::wstringのコンストラクターに、スレッドの最後のエラーコードをクリアする副作用がないことを保証できますか?確かにできないので、ステートメントの最初の行にある変数GetLastError()への古き良きアトミックな代入に呼び出しを移動します。DWORDcase

于 2010-10-15T20:01:19.670 に答える