System.Timers.Timer在调用timer.Stop()之后执行Elapsed事件

背景:我有一个计时器,用于跟踪自触发serialPort DataReceived事件以来已经过了多长时间。 我正在创建自己的解决方案,而不是使用内置的超时事件,因为我得到一个连续的数据流,而不是发送查询和获得一个响应。

问题:在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 temp = new List(report.Readings_Force); eventNewData(this, new eventArgsNewData(temp)); } 

这是众所周知的行为。 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(); } } 

我用这段代码暂停了计时器。 对我有用。

 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