【问题标题】:System.Timers.Timer Elapsed event executing after timer.Stop() is calledSystem.Timers.Timer 调用 timer.Stop() 后执行的 Elapsed 事件
【发布时间】:2013-08-16 19:00:05
【问题描述】:

背景:我有一个计时器,用于跟踪自触发 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));

    }

【问题讨论】:

    标签: c# .net timer


    【解决方案1】:

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

    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
    

    【讨论】:

      【解决方案2】:

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

      【讨论】:

      • 最后加上try的原因是什么?
      • @mikejames 在try 块中,您将添加您的逻辑,即使出现异常finally 块将确保您的计时器将重新启动。
      • 我认为这是有道理的,就我而言,我只希望计时器运行一次。我决定改成 System.Threading.Timer
      • @HilalAl-Rajhi System.Timers.Timer 有一个名为 AutoReset 的属性
      • 这不是在回答问题。问题是如何正确停止计时器,而不是阻止自动重置。
      【解决方案3】:

      遇到了同样的问题,经过一番尝试,最终将计时器对象设置为 null 并将计时器变量替换为新的计时器对象,从而解决了该问题。我知道它的资源很重。但它解决了问题。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2015-11-02
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-11-20
        相关资源
        最近更新 更多