我做了一个Window-Service,它在每个之后执行一个动作。我们已经将计时器声明如下:
using System.Timers;
....
Int32 myInterval = 60000 * (Convert.ToInt32(ConfigurationManager.AppSettings["lpInterval"].ToString()));
_myTimer = new Timer();
_myTimer.Interval = myInterval;
_myTimer.Elapsed += new ElapsedEventHandler(TimerElapsed);
//Timer-Tick
private void TimerElapsed(object source, ElapsedEventArgs e)
{ PerformAction(); }
注意到了什么:
如果PerformAction()
比我的interval
(由于WCF服务或服务器问题)花费的时间更长,则会启动并执行新的'instance'
PerformAction
。因此PerformAction
相互运行了两次(和parallel
)。
这是什么原因?为什么以前的PerformAction
没有被取消?方法PerformAction
是否正在执行Async
?
我找到了一种解决方法,但我只是不理解这种行为......
答案 0 :(得分:1)
在您执行操作之前停止计时器然后在执行操作后再次启动计时器
private void TimerElapsed(object source, ElapsedEventArgs e)
{
_myTimer.Stop();
PerformAction();
_myTimer.Start();
}
System.Timers
http://msdn.microsoft.com/en-us/library/system.timers.timer.elapsed(v=vs.110).aspx
在ThreadPool线程上引发了Elapsed事件。如果Elapsed事件的处理持续时间超过Interval,则可能会在另一个ThreadPool线程上再次引发该事件。在这种情况下,事件处理程序应该是可重入的。
在调用Dispose或Stop方法之后或在Enabled属性设置为false之后,可能会发生经过事件,因为提升Elapsed事件的信号始终排队等待在线程池线程上执行。解决此竞争条件的一种方法是设置一个标志,告诉事件处理程序Elapsed事件忽略后续事件。
答案 1 :(得分:1)
它只是计时器的设计决定。它有许多可能的解决方案,包括并行触发事件,排队处理程序,直到前一个处理程序完成后,完全跳过该特定事件。设计师选择了这个选项。他们可以很容易地选择另一个,就像某些其他计时器的设计师所做的那样。
至于为什么它没有被取消,非合作取消代码非常危险并且极易出错,并且滴答处理程序的实现通常不会感到需要实现合作取消(他们可以使用现有的实现,如果他们真的想要的话),所以这不是一个真正的选择。