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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/18280330/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-10 11:47:34  来源:igfitidea点击:

System.Timers.Timer Elapsed event executing after timer.Stop() is called

c#.nettimer

提问by TheColonel26

Background:I have a timer that I am using to keep track of how long it has been since the serialPort DataReceived event has been fired. I am creating my own solution to this instead of using the built in timeout event because I am getting a continuous stream of data, instead of sending a query and getting one response.

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

The Problem:In the DataReceived handler I have a statement to stop the timer so that is doesn't elapse. the problem is that a lot of the time it still executes the Elapsed handler afterword.

问题:在 DataReceived 处理程序中,我有一个语句来停止计时器,这样它就不会过去。问题是很多时候它仍然执行 Elapsed 处理程序后记。

I have read that is is possible to use SynchronizingObject to solve this problem but I am not sure how to accomplish that.

我读过可以使用 SynchronizingObject 来解决这个问题,但我不确定如何实现。

Here is my code:I tried to cut out everything that I didn't think was relevant.

这是我的代码:我试图删除我认为不相关的所有内容。

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

    }

采纳答案by Sriram Sakthivel

This is well known behavior. System.Timers.Timerinternally uses ThreadPoolfor execution. Runtime will queue the Timerin threadpool. It would have already queued before you have called Stopmethod. It will fire at the elapsed time.

这是众所周知的行为。System.Timers.Timer内部ThreadPool用于执行。运行时将Timer在线程池中排队。它会在您调用Stop方法之前已经排队。它会在经过的时间触发。

To avoid this happening set Timer.AutoResetto false and start the timer back in the elapsed handler if you need one. Setting AutoResetfalse makes timer to fire only once, so in order to get timer fired on interval manually start timer again.

为了避免这种情况发生,设置Timer.AutoReset为 false 并在需要时在经过处理的处理程序中重新启动计时器。设置AutoResetfalse 会使计时器仅触发一次,因此为了让计时器在间隔内触发,请再次手动启动计时器。

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

回答by Sketch

I did a pause in timer with this code. for me that works.

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

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

回答by amilamad

Had the same problem and after some trying ended up with timer object to null and replace the timer variable it with a new timer object fixed the issue. I know its heavy of resources. But it solves the problem.

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