Tengo un objeto de temporizador. Quiero que se ejecute cada minuto. Específicamente, debería ejecutar un OnCallBack
método y permanecer inactivo mientras OnCallBack
se ejecuta un método. Una vez que finaliza un OnCallBack
método, (a OnCallBack
) reinicia un temporizador.
Esto es lo que tengo ahora mismo:
private static Timer timer;
private static void Main()
{
timer = new Timer(_ => OnCallBack(), null, 0, 1000 * 10); //every 10 seconds
Console.ReadLine();
}
private static void OnCallBack()
{
timer.Change(Timeout.Infinite, Timeout.Infinite); //stops the timer
Thread.Sleep(3000); //doing some long operation
timer.Change(0, 1000 * 10); //restarts the timer
}
Sin embargo, parece que no funciona. Corre muy rápido cada 3 segundos. Incluso cuando se eleva un punto (1000 * 10). Parece que se hace de la vista gorda1000 * 10
¿Qué hice mal?
Timer.Change
: "Si dueTime es cero (0), el método de devolución de llamada se invoca inmediatamente". Parece que es cero para mí.Respuestas:
Este no es el uso correcto de System.Threading.Timer. Cuando crea una instancia del temporizador, casi siempre debe hacer lo siguiente:
Esto le indicará al temporizador que marque solo una vez cuando haya transcurrido el intervalo. Luego, en su función de devolución de llamada, cambia el temporizador una vez que se ha completado el trabajo, no antes. Ejemplo:
Por tanto, no hay necesidad de mecanismos de bloqueo porque no hay concurrencia. El temporizador disparará la siguiente devolución de llamada después de que haya transcurrido el siguiente intervalo + el tiempo de la operación de larga duración.
Si necesita ejecutar su temporizador exactamente en N milisegundos, le sugiero que mida el tiempo de la operación de larga duración usando Cronómetro y luego llame al método Cambiar de manera apropiada:
Recomiendo encarecidamente a cualquiera que esté usando .NET y esté usando CLR que no haya leído el libro de Jeffrey Richter: CLR a través de C # , que lo lea lo antes posible. Los temporizadores y los grupos de hilos se explican con gran detalle allí.
fuente
private void Callback( Object state ) { // Long running operation _timer.Change( TIME_INTERVAL_IN_MILLISECONDS, Timeout.Infinite ); }
.Callback
se puede volver a llamar antes de que se complete una operación.Long running operation
podría llevar mucho más tiempo entoncesTIME_INTERVAL_IN_MILLISECONDS
. ¿Qué pasaría entonces?ThreadPool
, si pasas el temporizador? Estoy pensando en un escenario en el que se genera un nuevo hilo para hacer un trabajo en un cierto intervalo, y luego se relega al grupo de hilos cuando se completa.No es necesario detener el temporizador, vea una buena solución en esta publicación :
"Puede dejar que el temporizador continúe activando el método de devolución de llamada, pero envuelva su código no reentrante en un Monitor. TryEnter / Exit. No es necesario detener / reiniciar el temporizador en ese caso; las llamadas superpuestas no adquirirán el bloqueo y regresarán inmediatamente".
fuente
¿Es
System.Threading.Timer
obligatorio el uso ?Si no es así,
System.Timers.Timer
tiene métodos prácticosStart()
yStop()
(y unaAutoReset
propiedad que puede establecer en falso, para queStop()
no sea necesario y simplemente llameStart()
después de ejecutar).fuente
Yo solo haría:
E ignore el parámetro de período, ya que está intentando controlar la periodicidad usted mismo.
Su código original se está ejecutando lo más rápido posible, ya que sigue especificando
0
eldueTime
parámetro. DeTimer.Change
:fuente
Change()
método?si quieres usar un hilo de bucle dentro ...
fuente