2008-10-23 9 views
8

Mi aplicación tiene varios hilos: 1) Tema principal 2) 2 Hilos Sub-principales (cada uno con bucle de mensajes, como se muestra a continuación), utilizados por TFQM 3) n subprocesos de trabajo (simple loop, que contiene Sleep())Delphi Multi-Threading Mensaje Loop

Mi problema es que cuando cierro mi aplicación, los subprocesos de trabajo logran salir correctamente, pero 1 de los 2 Sub-Main Threads se cuelga (nunca sale) cuando publico WM_QUIT para cerrarlos .


procedure ThreadProcFQM(P: Integer); stdcall; 
var 
    Msg: TMsg; 
_FQM: TFQM; 
begin 
    _FQM := Ptr(P); 
    try 
    _FQM.fHandle := AllocateHwnd(_FQM.WndProc); 

    while GetMessage(Msg, 0, 0, 0) do 
    begin 
     TranslateMessage(Msg); 
     DispatchMessage(Msg); 
    end; 

    finally 
    DeallocateHWnd(_FQM.fHandle); 
    SetEvent(_FQM.hTerminated); 
    end; 
end; 

procedure TFQM.Stop; 
begin 
    PostMessage(fHandle, WM_QUIT, 0, 0); 

    WaitForSingleObject(hTerminated, INFINITE); 
    if hThread <> INVALID_HANDLE_VALUE then 
    begin 
    CloseHandle(hThread); 
    hThread := INVALID_HANDLE_VALUE; 
    end; 
end; 

Respuesta

9

que he tenido el mismo problema, y ​​descubrí que no debería crear una ventana oculta simplemente para recibir los mensajes. Los hilos ya tienen un sistema de mensajes.

Creo que está creando su controlador de Windows y lo almacena en fHandle, pero GetMessage comprueba el bucle de mensajes de su hilo. Por lo tanto, el mensaje PostMessage (fHandle, WM_QUIT, 0, 0); nunca es recibido por el getmesssage.

Puede publicar mensajes en su hilo usando PostThreadMessage, y en el hilo usa GetMessage (CurrentMessage, 0, 0, 0). La única diferencia importante es que usted tiene que comenzar el bucle de mensajes desde su hilo llamando

PeekMessage(CurrentMessage, 0, WM_USER, WM_USER, PM_NOREMOVE); 

Usted debe comenzar con esto, de hacer su instalación y de iniciar su ciclo.

La razón por la que debe comenzar con el mensaje de asomarse es asegurarse de que los mensajes que se envían durante la inicialización de su proceso de subprocesos no se pierdan.

Lo raro es que, por el momento no puedo encontrar la referencia donde aprendí esto, pero mi suposición es la comunidad de grupos de noticias.

+0

Ooops, lo siento la primera vez que estoy aquí. No sabía acerca de los comentarios ... Lo intentaré. Gracias. – Atlas

+0

Davy tiene razón: debe usar PeekMessage para crear Message Queue – Remko

+0

Lo ha leído en la [página de MSDN para 'PostThreadMessage'] (http://msdn.microsoft.com/en-us/library/ms644946 (VS.85)) .aspx). Incluso recomiendan que el hilo principal espere un evento que el hilo establece una vez que se ha creado su mensaje. –

6

1) No necesita en AllocateHwnd dentro de su hilo. La primera llamada a GetMessage creará una cola de mensajes separada para este hilo. Pero para enviar un mensaje al hilo, debe usar la función PostThreadMessage.

Tenga en cuenta que en el momento de llamar a PostThreadMessage la cola todavía no se pudo crear. Usualmente uso construcción:

while not PostThreadMessage(ThreadID, idStartMessage, 0, 0) do 
    Sleep(1); 

para garantizar que se cree la cola de mensajes.

2) para la terminación de lazo de hilo que definir mi propio mensaje:

idExitMessage = WM_USER + 777; // you are free to use your own constant here 

3) No hay necesidad de evento separado, porque se puede pasar mango hilo para función WaitForSingleObject. Por lo tanto, el código podría ser:

PostThreadMessage(ThreadID, idExitMessage, 0, 0); 
    WaitForSingleObject(ThreadHandle, INFINITE); 

tener en cuenta que ThreadID y ThreadHandle son valores diferentes.

4) Por lo tanto, su ThreadProc se verá así:

procedure ThreadProcFQM; stdcall; 
var 
    Msg: TMsg; 
begin 
    while GetMessage(Msg, 0, 0, 0) 
    and (Msg.Message <> idExitMessage) do 
    begin 
    TranslateMessage(Msg); 
    DispatchMessage(Msg); 
    end; 
end; 
+0

Gracias, lo intentaré. – Atlas

+0

Como se señala a continuación, debe crear Message Queue con PeekMessage: // Force Message Queue Creation PeekMessage (Msg, 0, WM_USER, WM_USER, PM_NOREMOVE); – Remko

11

Si se me permite apuntar a algunos problemas en su código ...

1) Usted no está comprobando la salida de AllocateHwnd. Sí, lo más probable es que nunca falle, pero aún así ...

2) AllocateHwnd belogs FUERA de prueba ... ¡por fin! Si falla, no se debe llamar a DeallocateHwnd.

3) AllocateHwnd no es seguro para la rosca. Si lo llamas desde varios hilos al mismo tiempo, puedes toparte con poblems. Read more.

Como dijo Davy, usa MsgWaitForMultipleObjects en lugar de crear una ventana de mensaje oculto. Luego use PostThreadMessage para enviar mensajes al hilo.

Si puedo poner un enchufe para un producto totalmente gratis aquí - use mi OmniThreadLibrary en su lugar. Mucho más simple que jugar directamente con los mensajes de Windows.

+0

Gabr, gracias, pero su lib solo se limita a D2006 +? Estoy usando D7 ... – Atlas

+0

D2007 +, en realidad. Es hora de actualizar, entonces :) – gabr

+0

Gabr, su biblioteca de hilos parece fantástica, gracias por señalarlo. Ah, y diría que su sitio es "espartano", no feo. – Argalatyr