2013-08-16 6 views
7

Hintergrund: Ich habe einen Timer, den ich verwende, um zu verfolgen, wie lange es her ist, seit das serialPort DataReceived-Ereignis ausgelöst wurde. Ich erstelle meine eigene Lösung, anstatt das eingebaute Timeout-Ereignis zu verwenden, da ich einen kontinuierlichen Datenstrom bekomme, anstatt eine Abfrage zu senden und eine Antwort zu erhalten.System.Timers.Timer Abgelaufenes Ereignis, das nach dem Timer ausgeführt wird.Stop() heißt

Das Problem: Im DataReceived-Handler habe ich eine Anweisung, den Timer zu stoppen, so dass es nicht vergehen wird. Das Problem besteht darin, dass das Elapsed-Handler-Nachwort oft noch ausgeführt wird.

Ich habe gelesen, dass es möglich ist, SynchronizingObject verwenden, um dieses Problem zu lösen, aber ich bin mir nicht sicher, wie dies zu erreichen ist.

Hier ist mein Code: Ich habe versucht, alles auszuschneiden, was ich nicht für relevant hielt.

private System.Timers.Timer timeOut; 
    private System.Timers.Timer updateTimer; 

    public void start() 
    { 
     thread1 = new Thread(() => record()); 

     thread1.Start(); 
    } 

    public void requestStop() 
    { 
     this.stop = true; 
     this.WaitEventTest.Set(); 

    } 

    private void record() 
    { 
     timeOut = new System.Timers.Timer(500); //** .5 Sec 
     updateTimer = new System.Timers.Timer(500); //** .5 Sec 

     timeOut.Elapsed += TimeOut_Elapsed; 
     updateTimer.Elapsed += updateTimer_Elapsed; 
     updateTimer.AutoReset = true; 


     comport.Open(); 
     comport.DiscardInBuffer(); 


     comport.Write(COMMAND_CONTINUOUSMODE + "\r"); 

     stopwatch.Reset(); 
     stopwatch.Start(); 

     recordingStartTrigger(); //** Fire Recording Started Event 

     timeOut.Start(); 
     updateTimer.Start(); 

     this.waitHandleTest.WaitOne(); //** wait for test to end 

     timeOut.Stop(); 
     updateTimer.Stop(); 

     comport.Write(COMMAND_COMMANDMODE + Environment.NewLine); 
     comport.DiscardInBuffer(); 
     comport.Close(); 
     recordingStopTrigger(status); //** Fire Recording Stopped Event 

     stopwatch.Stop(); 
    } 


    //*********************************************************************************** 
    //** Events Handlers 


    private void comDataReceived_Handler(object sender, SerialDataReceivedEventArgs e) 
    { 

     double force = -100000; 
     string temp = "-100000"; 

     //timeOut.SynchronizingObject.Invoke(new Action(()=> {timeOut.Stop();}), new object[] {sender, e}); 

     timeOut.Stop(); 

     //** I removed my action code here, keep things simple. 


     timeOut.Start(); 
    } 

    private void TimeOut_Elapsed(object sender, System.Timers.ElapsedEventArgs e) 
    { 
     timeOut.Stop(); 
     updateTimer.Stop(); 


     //** fire delegate that GUI will be listening to, to update graph. 
     if (eventComTimeOut != null && this.stop == false) 
     { 
      if (eventComTimeOut(this, new eventArgsComTimeOut(comport.PortName, "READ"))) 
      { 
       //retry = true; 
       comport.Write(COMMAND_CONTINUOUSMODE + "\r"); 
       updateTimer.Start(); 
       timeOut.Start(); 
      } 
      else 
      { 
       this.stop = true; 
       //retry = false; 
       this.WaitEventTest.Set(); 
       status = eventArgsStopped.Status.failed;      
      } 
     } 
    } 

    void updateTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e) 
    { 

     //** fire delegate that GUI will be listening to, to update graph. 
     List<Reading> temp = new List<Reading>(report.Readings_Force); 
     eventNewData(this, new eventArgsNewData(temp)); 

    } 

Antwort

24

Dies ist wohlbekanntes Verhalten. System.Timers.Timer verwendet intern ThreadPool zur Ausführung. Runtime wird die Timer im Threadpool in die Warteschlange stellen. Es wäre bereits in der Warteschlange, bevor Sie Stop Methode aufgerufen haben. Es wird in der verstrichenen Zeit ausgelöst.

Um dies zu vermeiden, setzen Sie Timer.AutoReset auf "false" und starten Sie den Timer zurück in den verstrichenen Handler, wenn Sie einen brauchen. Die Einstellung AutoReset false bewirkt, dass der Timer nur einmal ausgelöst wird. Um den Timer auf Intervall zu setzen, starten Sie den Timer erneut manuell.

yourTimer.AutoReset = false; 

private void Timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e) 
{ 
    try 
    { 
     // add your logic here 
    } 
    finally 
    { 
     yourTimer.Enabled = true;// or yourTimer.Start(); 
    } 
} 
+2

@Downvoter Kommentar? –

+0

Was ist der Grund dafür, den Versuch endlich hinzuzufügen? –

+5

@mikejames Im 'try' Block fügen Sie Ihre Logik hinzu, selbst im Falle von Ausnahmen wird 'finally' block sicherstellen, dass yourTimer erneut gestartet wird. –

2

Ich habe eine Pause im Timer mit diesem Code gemacht. das funktioniert für mich.

Private cTimer As New System.Timers.Timer 
Private Sub inittimer() 
    cTimer.AutoReset = True 
    cTimer.Interval = 1000 
    AddHandler cTimer.Elapsed, AddressOf cTimerTick 
    cTimer.Enabled = True 
End Sub 

Private Sub cTimerTick() 
    If cTimer.AutoReset = True Then 
     'do your code if not paused by autoreset false 
    End If 
End Sub 
Verwandte Themen