2010-07-22 12 views
18

Tengo un TTimer en mi aplicación que se dispara cada 2 segundos y llama a mi controlador de eventos, HandleTimerEvent(). La función HandleTimerEvent() modifica los recursos compartidos y puede tardar 10 segundos en ejecutarse antes de volver. Además, llamo a Sleep() en el controlador de eventos para renunciar al procesador a veces.¿Está el reentrante del controlador de eventos TTimer.OnTimer?

No estoy seguro de cómo funciona el objeto TTimer del generador de C++ cuando se trata de llamar eventos, por lo que el escenario que acabo de explicar me hace pensar, particularmente, si se llama a HandleTimerEvent() antes de que se devuelva una llamada anterior.

La pregunta se reduce a un par de cosas.

¿El objeto TTimer pone en cola los eventos?

¿Puede el objeto TTimer llamar a mi controlador de eventos antes de que haya respondido una llamada anterior?

Respuesta

31

Esta respuesta asume que TTimer todavía está implementado para usar mensajes WM_Timer. Si la implementación ha cambiado (desde 2005), ignórelo.

No, el objeto TTimer no pone eventos en cola. Está impulsado por el mensaje Windows WM_Timer, y Windows no permite que los mensajes WM_TIMER se acumulen en la cola de mensajes. Si se produce el siguiente intervalo del temporizador y Windows ve que un mensaje WM_Timer ya está en la cola de mensajes de la aplicación, no agrega otro mensaje WM_Timer a la cola. (Lo mismo para WM_Paint, btw)

Sí, es posible que se active un evento TTimer.OnTimer incluso mientras un controlador de eventos anterior aún se está ejecutando. Si hace algo en su controlador de eventos que le permite a la aplicación procesar mensajes, entonces su evento de temporizador puede ser reingresado. El más obvio es si su controlador de eventos llama a Application.ProcessMessages, pero puede ser mucho más sutil que eso; si algo llama en su controlador de eventos llama internamente a Application.ProcessMessages, o llama a PeekMessage/GetMessage + DispatchMessage, o abre un diálogo modal o llama a una interfaz COM que está vinculada a un objeto COM fuera de proceso, los mensajes en la cola de mensajes de la aplicación se procesarán y podrían incluir su próximo mensaje WM_Timer.

Una solución simple es desactivar el objeto del temporizador cuando ingresa su controlador de eventos del temporizador, y volver a activarlo cuando salga de su controlador de eventos del temporizador. Esto evitará que se activen los mensajes del temporizador mientras el controlador de eventos todavía está funcionando, independientemente de las características de manejo de mensajes de su código.

+10

+1 para deshabilitar el temporizador. Para demostrar la efectividad de deshabilitar el temporizador (o una demostración fácil de lo que puede salir mal si no lo hace), muestre un cuadro de mensaje en el controlador del temporizador. Si no desactiva el temporizador al ingresar, los cuadros de mensajes se acumularán. –

+2

También puede usar un indicador booleano para evitar la reentrada en el controlador de eventos del temporizador, pero deshabilitar el temporizador en sí es mucho más simple. – dthorpe

+0

Consulte https://forums.embarcadero.com/thread.jspa?messageID=171751𩻧 para obtener una clase TTimerGuard útil, una clase de estilo RAII para el uso de TTimer. Puede ser necesario ajustar el uso de FInterval según su implementación. –

2

Uso TTimer extensivamente. No pone eventos en cola. Si desea que se transfiera a un controlador de eventos, cree un TThread que maneje sus eventos para que el temporizador pueda continuar con su trabajo. El temporizador no funciona de manera asíncrona, sino sincrónica.

Cuestiones relacionadas