2009-05-02 18 views
12

Tengo un temporizador que no necesita procesar su manejador de eventos transcurrido al mismo tiempo. Pero procesar un evento transcurrido puede interferir con otros. Implementé la solución a continuación, pero algo parece estar mal; parece que debería usar el temporizador de forma diferente o usar otro objeto dentro del espacio de enhebrado. El cronómetro pareció encajar mejor porque necesito verificar periódicamente el estado, pero a veces la verificación tomará más tiempo que mi intervalo. ¿Es esta la mejor manera de abordar esto?¿Cómo bloquear un temporizador mientras se procesa el evento transcurrido?

// member variable 
private static readonly object timerLock = new object(); 
private bool found = false; 


// elsewhere 
timer.Interval = TimeSpan.FromSeconds(5).TotalMilliseconds; 
timer.Elapsed = Timer_OnElapsed; 
timer.Start(); 


public void Timer_OnElapsed(object sender, ElapsedEventArgs e) 
{ 
    lock(timerLock) 
    { 
    if (!found) 
    { 
     found = LookForItWhichMightTakeALongTime(); 
    } 
    } 
} 
+2

Esto no debería haber sido una wiki de la comunidad. – Samuel

+0

@Samuel: cualquier pregunta puede ser wiki de la comunidad si el póster lo desea. Las preguntas frecuentes solo especifican que algunas preguntas deben ser wiki de la comunidad desde el principio, pero no restringen la aplicación de CW a ninguna pregunta. – tvanfosson

+1

@tvanfosson: Le estaba haciendo saber que preguntas como estas no deberían ser wiki de la comunidad. – Samuel

Respuesta

13

Puede establecer AutoReset en false, luego restablecer explícitamente el temporizador después de haber terminado de manejarlo. Por supuesto, la forma de manejarlo realmente depende de cómo espere que funcione el temporizador. Hacerlo de esta manera permitiría que su temporizador se aleje del intervalo especificado real (como lo haría para detener y reiniciar). Su mecanismo permitiría que cada intervalo se desencadene y se maneje, pero puede ocasionar un retraso en los eventos no controlados que se manejan ahora cerca del vencimiento del temporizador que causa la invocación del controlador.

timer.Interval = TimeSpan.FromSeconds(5).TotalMilliseconds; 
timer.Elapsed += Timer_OnElapsed; 
timer.AutoReset = false; 
timer.Start(); 


public void Timer_OnElapsed(object sender, ElapsedEventArgs e) 
{ 
    if (!found) 
    { 
     found = LookForItWhichMightTakeALongTime(); 
    } 
    timer.Start(); 
} 
+0

AutoReset y Elapsed son para System.Threading.Timer que no es seguro para el trabajo de IU. – Samuel

+0

@Samuel: transcurrido es el evento que está utilizando el OP. Presumiblemente, esta no es una aplicación de WinForms. – tvanfosson

8

Normalmente me parada del temporizador durante el procesamiento, ingrese a/por último bloque try, y reanudar el temporizador cuando haya terminado.

0
timer.enabled = false 

o

timer.stop(); 

y

timer.enabled = true 

o

timer.start(); 
-1

uso el System.Threading.Timer como tan

class Class1 
    { 
     static Timer timer = new Timer(DoSomething,null,TimeSpan.FromMinutes(1),TimeSpan.FromMinutes(1)); 

     private static void DoSomething(object state) 
     { 
      timer = null; // stop timer 

      // do some long stuff here 

      timer = new Timer(DoSomething, null, TimeSpan.FromMinutes(1), TimeSpan.FromMinutes(1)); 
     } 



    } 
+1

Siempre debe deshacerse de las instancias del temporizador cuando haya terminado con ellas. –

+0

El temporizador seguirá activando el método de devolución de llamada siempre que el recolector de basura no lo haya limpiado.Esto puede causar efectos inesperados y no deterministas. –

1

Si LookForItWhichMightTakeALongTime() va a llevar mucho tiempo, sugeriría no usar un System.Windows.Forms.Timer ya que al hacerlo se bloqueará el subproceso de interfaz de usuario y el usuario puede matar a su aplicación a pensar que se ha congelado.

Lo que podría usar es un BackgroundWorker (junto con un Timer si así lo desea).

public class MyForm : Form 
{ 
    private BackgroundWorker backgroundWorker = new BackgroundWorker(); 

    public MyForm() 
    { 
    InitializeComponents(); 
    backgroundWorker.DoWork += backgroundWorker_DoWork; 
    backgroundWorker.RunWorkerCompleted += 
           backgroundWorker_RunWorkerCompleted; 
    backgroundWorker.RunWorkerAsync(); 
    } 

    private void backgroundWorker_DoWork(object sender, DoWorkEventArgs e) 
    { 
    e.Result = LookForItWhichMightTakeALongTime(); 
    } 

    private void backgroundWorker_RunWorkerCompleted(object sender, 
              RunWorkerCompletedEventArgs e) 
    { 
    found = e.Result as MyClass; 
    } 
} 

Y puede llamar RunWorkerAsync() desde cualquier lugar que desee, incluso desde un Timer si lo desea. Y solo asegúrese de comprobar si el BackgroundWorker ya se está ejecutando desde que llamó al RunWorkerAsync() cuando se está ejecutando lanzará una excepción.

private void timer_Tick(object sender, EventArgs e) 
{ 
    if (!backgroundWorker.IsBusy) 
    backgroundWorker.RunWorkerAsync(); 
} 
Cuestiones relacionadas