Question

J'ai un fil qui crée des objets COM qui nécessitent un appartement fileté.

A l'origine, la fonction principale de ce fil, il a mis dans une boucle WaitForMultipleObjects. De toute évidence cela est un problème, car il empêche la pompe de message COM de le faire du travail.

Je l'ai remplacé avec ce MsgWaitForMultipleObjects comme une solution, mais maintenant je suis en cours d'exécution dans un problème: MsgWaitForMultipleObjects parfois des retours (souvent) WAIT_FAILED, mais ne fixe pas une erreur.

Le code gère une valeur de retour WAIT_FAILED par juste continuer et d'essayer d'appeler MsgWaitForMultipleObjects à nouveau. L'appel à MsgWaitForMultipleObjects peut renvoyer un WAIT_FAILED plusieurs fois (le plus que je l'ai vu est 9), mais il fonctionne soudainement sans problème.

Le code est écrit de telle sorte que cela pourrait aller dans une boucle infinie si la fonction était de retour WAIT_FAILED pour une raison valable. Je sais que je dois résoudre ce problème, mais pour le moment je considère un « travail autour » parce que l'appel MsgWaitForMultipleObjects finira par réussir.

Ce code est testé sur Windows 7, Vista et XP (toutes les 32 bits, Windows 7 32 bits et 64 bits).

Est-ce que quelqu'un a une idée pourquoi cela se passe?

Le code correspondant:

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

Exemple de sortie serait:

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

Je crois que la valeur de retour WAIT_FAILED se produit seulement après que l'attente a été interrompue par un message.

Était-ce utile?

La solution

Cela ne devrait pas se produire, et je suis sûr ne peut pas expliquer exactement pourquoi il le fait. J'ai quelques conseils, cependant.

D'abord, vous n'êtes pas appeler TranslateMessage() avant DispatchMessage() dans votre pompe de message. C'est mauvais juju, et vous ne voulez pas mal juju partout près MsgWaitForMultipleObjects().

Vous pouvez également essayer d'appeler explicitement MsgWaitForMultipleObjectsEx(), juste au cas où il ne présente pas le même problème:

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

Enfin, il pourrait être tiré par les cheveux, mais bien considérer ce qui se passe après le retour de MsgWaitForMultipleObjects() et avant GetLastError() est appelé. Abstraction faite de l'affectation à ret, je vois un appel implicite au constructeur de std::wstring.

Pouvez-vous garantir le constructeur de std::wstring n'a pas un effet secondaire qui efface le dernier code d'erreur du fil? Je ne peux pas vous, donc je passer l'appel à GetLastError() en un bon, à l'ancienne, l'affectation atomique à une variable DWORD dans la première ligne de la déclaration de case.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top