Pregunta

Tengo un hilo que crea objetos COM que requieren un apartamento individual roscado.

En un principio, la función principal de este hilo puso en un bucle WaitForMultipleObjects. Evidentemente esto es un problema, ya que evita que el suministro de mensajes COM de hacer su trabajo.

He reemplazado esto con MsgWaitForMultipleObjects como una solución, pero ahora estoy corriendo en un tema: MsgWaitForMultipleObjects veces (a menudo) vuelve WAIT_FAILED, pero no establece un error.

El código controla un valor de retorno WAIT_FAILED con sólo continua y tratando de llamar MsgWaitForMultipleObjects nuevo. La llamada a MsgWaitForMultipleObjects puede devolver WAIT_FAILED un par de veces (la mayoría que he visto es 9), pero luego de repente funciona sin ningún problema.

El código está escrito para que esto podría ir en un bucle infinito si la función se vuelve WAIT_FAILED por una razón válida. Sé que debería solucionar este problema, pero en el momento que estoy teniendo en cuenta que un 'trabajo en torno a' porque la llamada MsgWaitForMultipleObjects finalmente tener éxito.

Este código está siendo probado en Windows 7, Vista, y XP (todos de 32 bits, Windows 7 de 32 y 64 bits).

¿Alguien tiene alguna idea de por qué está sucediendo esto?

El código relevante:

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

Ejemplo de salida sería:

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

Creo que el valor de retorno WAIT_FAILED sólo se está produciendo después de la espera ha sido roto por un mensaje.

¿Fue útil?

Solución

Esto no debería estar sucediendo, y estoy seguro que no puede explicar exactamente ¿Por qué lo hace. Tengo algunas sugerencias, sin embargo.

En primer lugar, usted no está llamando antes de TranslateMessage() DispatchMessage() en su suministro de mensajes. Eso es malo juju, y que no quieren mala juju en cualquier lugar cerca MsgWaitForMultipleObjects().

También puede ser que desee para tratar de forma explícita llamando MsgWaitForMultipleObjectsEx(), en caso de que no presenta el mismo problema:

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

Por último, podría ser exagerado pero tenga en cuenta lo que está sucediendo después del retorno de MsgWaitForMultipleObjects() y antes GetLastError() se llama. Sin tener en cuenta la asignación de ret, veo una llamada implícita al constructor de std::wstring.

Pueden garantizar el constructor de std::wstring no tiene algún efecto secundario que borra último código de error del hilo? Estoy seguro que no puede, por lo que movería la llamada a GetLastError() en un bien, pasado de moda, la asignación a una variable atómica DWORD en la primera línea de la declaración case.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top