2012-06-02 11 views
15

Tengo una aplicación cuyo segundo hilo llama a GetMessage() en un bucle. En algún momento, el primer hilo se da cuenta de que el usuario desea salir de la aplicación y notifica al segundo hilo que debe terminar. Como el segundo hilo está atascado en GetMessage(), el programa nunca se cierra. ¿Hay alguna forma de esperar mensajes con un tiempo de espera excedido? Estoy abierto a otras ideas también.GetMessage con un tiempo de espera

EDIT: (explicaciones adicionales)

El segundo hilo corre que fragmento de código:

while (!m_quit && GetMessage(&msg, NULL, 0, 0)) 
{ 
    TranslateMessage(&msg); 
    DispatchMessage(&msg); 
} 

El primer hilo establece m_quit a verdadero.

+0

Espera ... ¿qué hilo está en espera esperando 'GetMessage()'? ¿El primer hilo, el segundo hilo o ambos? – templatetypedef

+0

El segundo subproceso ejecuta el bucle GetMessage. ¿Debo publicar algún código? – qdii

+0

Código siempre ayuda. Estoy confundido porque tu pregunta parece que ambos hilos están bloqueados. ¿No puedes enviar un mensaje personalizado que diga "debes cerrar ahora?" – templatetypedef

Respuesta

13

La manera más fácil es simplemente llamar al UINT_PTR timerId=SetTimer(NULL, NULL, 1000, NULL) antes de llamar al GetMessage. Publicará un mensaje WM_TIMER en el hilo de llamada cada segundo, por lo que el GetMessage volverá puntualmente. Luego, llame al KillTimer(NULL, timerId) para cancelarlo.

actualización de código muestra:

BOOL GetMessageWithTimeout(MSG *msg, UINT to) 
{ 
    BOOL res; 
    UINT_PTR timerId = SetTimer(NULL, NULL, to, NULL); 
    res = GetMessage(msg); 
    KillTimer(NULL, timerId); 
    if (!res) 
     return FALSE; 
    if (msg->message == WM_TIMER && msg->hwnd == NULL && msg->wParam == timerId) 
     return FALSE; //TIMEOUT! You could call SetLastError() or something... 
    return TRUE; 
} 
+0

Rather extraño perro guardián =) – Forgottn

+0

@rodrigo: +1. hasta ahora la mejor solución que he visto. Esperaré a que aparezcan otros candidatos. – qdii

+0

@rodrigo cuidado con 'msg' es un puntero. también, la estructura puntiaguda no tiene un miembro 'uMsg', se llama' mensaje'. – qdii

-1

Yep. Pruebe PeekMessage() en su lugar. Pero creo que esto no será una solución de problemas completa.

+0

@Forgoth Calling 'PeekMessage()' sería una gran solución si pudiera juntarlo con 'Sleep (1000)', pero en mi caso el segundo hilo debería ser muy reactivo. +1 porque la solución es válida en otros contextos – qdii

4

Una cosa que siempre se puede hacer es enviar el hilo bloqueado un mensaje definido por el usuario que va a hacer que se despierte, procesar el mensaje, a continuación, volver a subir a la cima del bucle De hecho, podría ser más fácil eliminar por completo la variable m_quit y, en su lugar, simplemente enviar el mensaje principal que dice "debe salir ahora".

Espero que esto ayude!

+1

+1, Esto ayuda. Yo prefiero la solución de Rodrigo, ya que mantiene el mecanismo completo para dejar de fumar en un solo lugar. – qdii

+1

Este es un método mucho más limpio. El objetivo del hilo es recibir mensajes que le digan qué hacer. Y esto no requiere que el hilo se active constantemente cuando no hay nada que hacer. –

2

Debería poder enviar un mensaje de abandono al segundo hilo con PostThreadMessage.

E.g.

PostThreadMessage(threadid, WM_QUIT, 0, 0); 

No debería ser necesario para leer la variable m_quit en el segundo hilo, pero usted debe comprobar si hay errores de GetMessage, así como un valor de retorno de FALSE/0 que es lo que se devuelve si el siguiente mensaje es un mensaje de dejar de fumar .

18

No probado, pero puede probar la función MsgWaitForMultipleObjects sin ningún objeto.

MsgWaitForMultipleObjects(0, NULL, FALSE, timeout, QS_ALLEVENTS); 

Si si los rendimientos WAIT_TIMEOUT es un tiempo de espera, pero si devuelve WAIT_OBJECT_0 puede llamar GetMessage con garantía de no ser bloqueado.

Pero tenga en cuenta los siguientes:

MsgWaitForMultipleObjects no vuelve si hay entrada sin leer del tipo especificado en la cola de mensajes después de que el mensaje ha llamado una función para comprobar la cola.

Así que debe asegurarse de que la última vez que llamó a cualquiera de las funciones del mensaje no quede ningún mensaje en la cola, o tendrá una especie de condición de carrera.

Probablemente su mejor opción sería la de sustituir GetMessage con:

if (MsgWaitForMultipleObjects(0, NULL, FALSE, timeout, QS_ALLEVENTS) == WAIT_OBJECT_0) 
{ 
    while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) 
    { 
     //dispatch the message 
    } 
} 

Pero como he dicho antes, no he probado, así que no puede estar seguro de si va a trabajar.

+1

ah eso es mejor evento – qdii

+8

Acabo de tener un punto muerto esperando un mensaje ** SendMessage ** con esta rutina. Debería usar ** QS_ALLINPUT ** en lugar de ** QS_ALLEVENTS **, porque también cubre ** QS_SENDMESSAGE **. vea [msdn] (http://msdn.microsoft.com/en-us/library/windows/desktop/ms684242%28v=vs.85%29.aspx) para más información – 5andr0

+0

Gracias @ 5andr0 el 'QS_ALLINPUT' fue lo que ¡Me lo arregló! – Noitidart

Cuestiones relacionadas