Pregunta

Hay un subproceso en mi aplicación Delphi que tiene un bucle de mensaje en espera. Cada vez que recibe un mensaje, comienza a hacer algún trabajo. Aquí está el procedimiento de ejecución de ese hilo:

procedure TMyThread.Execute;
begin
  while GetMessage(Msg, 0, 0, 0) and not Terminated do
  begin
    {thread message}
    if Msg.hwnd = 0 then
    begin
      ...
    end
    else
      DispatchMessage(Msg);
  end;
end;

Al realizar algunas pruebas con mi aplicación, descubrí que la función GetMessage depende del hilo principal. Con esto quiero decir que mientras el subproceso principal está haciendo algún trabajo, la función GetMessage en mi subproceso no vuelve a pesar de que un mensaje está esperando para ser recibido por él (el mensaje es enviado por otro subproceso utilizando la función PostThreadMessage: PostMessage MyThreadId, WM_MyMessage, 0, 0)).

Solo cuando el hilo principal finaliza su trabajo o se llama al método Application.ProcessMessages, GetMessage regresa y mi hilo comienza a hacer su trabajo. Al implementar este tipo de comunicación entre subprocesos, estaba seguro de que mis subprocesos funcionarán de forma independiente y nunca esperaría que la recepción de mensajes enviados directamente a un subproceso dependiera del subproceso principal.

Haciendo las pruebas, utilicé la función WaitForSingleObject en el hilo principal, esperando un evento durante unos segundos. Esto es cuando noté que mi hilo no estaba haciendo ningún trabajo a pesar de que los mensajes fueron enviados por otro hilo. Cuando la función WaitForSingleObject finalmente terminó de esperar y el subproceso principal quedó inactivo, la función GetMessage en mi subproceso regresó.

¿Podría alguien explicarme por qué funciona de esta manera? ¿Hay una solución a eso? Me gustaría que mi hilo reciba mensajes de forma independiente. Todos mis hilos son creados por el hilo principal. ¿Puede ser esta la razón?

Gracias por su ayuda de antemano.

Mariusz.


Mghie, volviste a tener toda la razón (últimamente me has ayudado con los mensajes, puedes recordar). Como sugirió, GetMessage regresa inmediatamente, pero el hilo se bloquea, de hecho, en una llamada a un método de ventana principal:

procedure TMyThread.Execute;
begin
  while GetMessage(Msg, 0, 0, 0) and not Terminated do
  begin
    {thread message}
    if Msg.hwnd = 0 then
    begin
      ...
      if Assigned(FOnCommEventMethod) then
        FOnCommEventMethod(FCommEventsQueueItem);
      ...
    end
    else
      DispatchMessage(Msg);
  end;
end;

FOnCommEventMethod es un método de objeto, declarado como 'procedimiento (EventMask: Cardinal) de objeto;' (este hilo maneja eventos de puerto serie). En este caso, se asignó a FOnCommEventMethod un procedimiento que pertenece a la clase de formulario principal. Cuando mi hilo llama al método, el hilo se cuelga esperando que el hilo principal termine su trabajo.

¿cómo es que? Como puede ver, no uso el método Synchronize () para llamar a este procedimiento. Por lo tanto, no esperaría que mi hilo se sincronice con el hilo principal. ¿Ocurre implícitamente? Por cierto, entiendo que no se debe acceder a ningún componente de la GUI por ningún otro subproceso que no sea el principal, por lo que se debe usar el método de Sincronización, pero ahora solo estoy haciendo algunas pruebas rápidas.

Volviendo al tema WaitForSingleObject, sé que no debería usarlo, pero fue solo una prueba gracias a la cual (casualmente) noté el problema.

Gracias por tu ayuda. Si no me ayudara, probablemente me desharía de la mensajería y usaría los eventos, y finalmente me daría cuenta de que no era la razón :-).

¿Fue útil?

Solución

  

Solo cuando el subproceso principal finaliza su trabajo o se llama al método Application.ProcessMessages, GetMessage regresa y mi hilo comienza a hacer su trabajo.

Dudo que esto sea realmente lo que está pasando. AFAIK los dos bucles de mensajes deben ser independientes entre sí, siempre y cuando no utilices otros medios para sincronizar los hilos, como SendMessage () . ¿Está seguro de que el hilo se bloquea dentro de GetMessage () y no dentro de Synchronize () (que está usando SendMessage () internamente )?

  

Haciendo las pruebas, usé la función WaitForSingleObject en el hilo principal, esperando un evento por unos segundos.

Nunca debe usar WaitForSingleObject () en el hilo principal con un tiempo de espera superior a, por ejemplo, 100 milisegundos, ya que esto hará que su GUI parezca lenta. De hecho, le aconsejaría que no lo use en absoluto en el hilo principal, porque esto es simplemente un sondeo. Publica un mensaje desde el hilo de tu trabajador en su lugar.

Otros consejos

Puedes crear una cola de mensajes para tu hilo. Simplemente ejecuta el siguiente código en tu hilo:

MSG msg;
PeekMessage(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE);
SetEvent(messageQueueReady);
while (GetMessage(&msg, NULL, 0, 0)) 
{
    ...// do message processing here
}

La llamada a PeekMessage obliga al sistema operativo a crear una nueva cola de mensajes para su hilo. Debe asegurarse de sincronizar esto, es decir, tiene que esperar (por ejemplo, a través de WaitForSingleObject) para que la llamada tenga éxito antes de publicar mensajes en este hilo (por ejemplo, a través de PostThreadMessage). Esta es la razón por la que hay una llamada a la API SetEvent en el ejemplo anterior.

Editar: Lo siento por el ejemplo que está en C, espero que esté bien para ti.

Consulte http: // groups.google.com/group/borland.public.delphi.language.delphi.win32/browse_thread/thread/cf368834a606321b

Destilación solicitada, dejando de lado muchos detalles retorcidos en los que se esconde el diablo: el hilo principal (o VCL) es especial en Delphi porque muchas cosas bajo el capó no son seguras, y son las propias. Cosas como el bucle de mensajes terminan esperando debido a cosas que se sincronizan con el hilo VCL debajo del capó. Muchas personas tienen teorías sobre esto. Lo que parece funcionar mejor es mantener el hilo VCL lo más ligero / sensible posible para minimizar las esperas. Todos están bastante de acuerdo con esto. Algunas personas tienen ideas sobre otras cosas que podrían funcionar, pero otras piensan que solo están pidiendo problemas.

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