Domanda

Ho un filo che crea gli oggetti COM che richiedono un unico appartamento filettato.

In origine, la funzione principale di questa discussione ha messo in un ciclo WaitForMultipleObjects. Evidentemente questo è un problema, perché impedisce alla pompa messaggio COM dal fare il suo lavoro.

ho sostituito questo con MsgWaitForMultipleObjects come una soluzione, ma ora sto correndo in un problema: MsgWaitForMultipleObjects a volte (spesso) i rendimenti WAIT_FAILED, ma non imposta un errore.

Il codice gestisce un valore di ritorno WAIT_FAILED semplicemente continuando e cercando di chiamare di nuovo MsgWaitForMultipleObjects. La chiamata a MsgWaitForMultipleObjects possono restituire WAIT_FAILED un paio di volte (il massimo che ho visto è 9), ma poi funziona improvvisamente senza alcun problema.

Il codice è scritto in modo che questo potrebbe potenzialmente entrare in un ciclo infinito se la funzione stavano tornando WAIT_FAILED per un motivo valido. So che dovrei risolvere questo problema, ma al momento sto valutando un 'lavoro intorno' perché la chiamata MsgWaitForMultipleObjects finirà per avere successo.

Questo codice è stato testato su Windows 7, Vista e XP (tutte a 32 bit, Windows 7 a 32 e 64 bit).

Qualcuno ha qualche idea del perché questo sta accadendo?

Il codice in questione:

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

uscita esempio potrebbe essere:

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

Credo che il valore di ritorno WAIT_FAILED è solo che si verifica dopo l'attesa è stata interrotta da un messaggio.

È stato utile?

Soluzione

Questo non deve accadere, e io certo non può spiegare esattamente perché che fa. Io ho alcune indicazioni, tuttavia.

In primo luogo, non si sta chiamando prima di TranslateMessage() DispatchMessage() in pompa messaggio. Questo è male juju, e non si vuole male juju da nessuna parte vicino MsgWaitForMultipleObjects().

È inoltre potrebbe desiderare di provare in modo esplicito chiamare MsgWaitForMultipleObjectsEx(), nel caso in cui esso non presenta lo stesso problema:

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

Infine, potrebbe essere inverosimile, ma prendere in considerazione quello che succede dopo ritorna MsgWaitForMultipleObjects() e prima GetLastError() si chiama. Trascurando l'incarico di ret, vedo una chiamata implicita al costruttore di std::wstring.

Può garantire il costruttore di std::wstring non ha alcun effetto collaterale che cancella ultimo codice di errore del thread? Sono sicuro che non è possibile, quindi mi piacerebbe spostare la chiamata a GetLastError() in un buon, vecchio stile, l'assegnazione ad una variabile atomica DWORD nella prima riga della dichiarazione case.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top