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
System.Timers.Timer Elapsed event executing after timer.Stop() is called
提问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.Timer
internally uses ThreadPool
for execution. Runtime will queue the Timer
in threadpool. It would have already queued before you have called Stop
method. It will fire at the elapsed time.
这是众所周知的行为。System.Timers.Timer
内部ThreadPool
用于执行。运行时将Timer
在线程池中排队。它会在您调用Stop
方法之前已经排队。它会在经过的时间触发。
To avoid this happening set Timer.AutoReset
to false and start the timer back in the elapsed handler if you need one. Setting AutoReset
false makes timer to fire only once, so in order to get timer fired on interval manually start timer again.
为了避免这种情况发生,设置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();
}
}
回答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.
遇到了同样的问题,经过一些尝试后,计时器对象最终为空,并将计时器变量替换为新的计时器对象,解决了该问题。我知道它的资源很重。但它解决了问题。