System.Timers.Timer在计时器之后执行的经过时间事件.调用了Stop()

本文关键字:调用 事件 时间 Stop 经过 Timer Timers 计时器 执行 之后 System | 更新日期: 2023-09-27 18:28:07

背景:我有一个计时器,用来跟踪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<Reading> temp = new List<Reading>(report.Readings_Force);
        eventNewData(this, new eventArgsNewData(temp));
    }

System.Timers.Timer在计时器之后执行的经过时间事件.调用了Stop()

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

也遇到了同样的问题,经过一段时间的尝试,计时器对象为null并用新的计时器对象替换计时器变量,解决了这个问题。我知道这里资源丰富。但它解决了问题。

我在Elapsed事件中添加了一个检查

if(_timer.Enabled)
{
   //Do something
}