2013-08-16 46 views
7

背景:我有一個計時器,我用它來跟蹤自從serialPort DataReceived事件被觸發以來它已經持續了多長時間。我正在創建自己的解決方案,而不是使用內置的超時事件,因爲我正在獲取連續的數據流,而不是發送查詢並獲得一個響應。System.Timers.Timer在timer.Stop()被調用後執行已經執行的事件

問題: 在DataReceived處理程序中,我有一條語句來停止計時器,以便不會過去。問題是很多時候它仍然執行Elapsed處理程序。

我讀過,這是可以使用SynchronizingObject來解決這個問題,但我不知道如何做到這一點。

這是我的代碼:我試圖剪掉所有我認爲不相關的東西。

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)); 

    } 

回答

24

這是衆所周知的行爲。 System.Timers.Timer內部使用ThreadPool執行。運行時將在線程池中排列Timer。在您調用Stop方法之前,它已經排隊。它會在經過的時間點燃。

爲避免發生這種情況,請將Timer.AutoReset設置爲false,並在需要的處理程序中啓動計時器。設置AutoReset false使定時器只觸發一次,所以爲了讓定時器在間隔時間內手動啓動定時器啓動定時器。

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有何評論? –

+0

最後加入try的原因是什麼? –

+5

@mikejames在'try'塊中,你會添加你的邏輯,即使在例外的情況下,finally塊也會確保你的定時器將再次啓動。 –

2

我在這段代碼中做了一個暫停計時器。對我來說這是有效的。

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