我遇到与本主题How to let Timer skip tick if the previous thread is still busy
中描述的问题相同的问题我不知道是否应该为我的问题创建新主题,或者我可以“以某种方式”存在的线程(请告诉我,如果我错误地创建新主题)
我写了这样的解决方案:
Mutex refreshMutex = new Mutex();
void OnRefreshTimedEvent(object source, ElapsedEventArgs args)
{
try
{
refreshMutex.WaitOne();
// do work
} finally
{
refreshMutex.ReleaseMutex();
}
}
我认为它更好,因为它是线程安全的并且不会锁定entiry对象。我很感激任何评论因为我在C#中非常新手:)
有没有人看到我分享的任何潜在问题?我不能在另一个讨论中作为答案。
upd 好吧上面的解决方案似乎不起作用(感谢user24601注意)。但我不喜欢引用问题的答案,因为对serviceTimer.Stop()的调用不是线程安全的。在理论上(并且可能实际上)极端频繁的定时器可能是一个问题,特别是如果系统被集中使用(100%CPU负载等)。我现在在考虑这种模式:
[MethodImpl(MethodImplOptions.Synchronized)]
void serviceTimer_Elapsed(object sender, ElapsedEventArgs e)
{
try
{
serviceTimer.Stop();
// do some heavy processing...
}
finally
{
serviceTimer.Start();
}
}
答案 0 :(得分:2)
这实际上并没有解决问题。 Elapsed事件在线程池线程上引发。当您的应用程序中存在大量活动TP线程时,调用Elapsed事件处理程序的线程可能需要几秒钟才能开始运行。事实上,在发生这种延迟时,可能会安排其中几个。停止计时器不阻止这些延迟线程运行。您仍然可以有多个线程同时调用您的Elapsed事件处理程序。
将计时器的AutoReset属性设置为False。在Elapsed事件处理程序的finally块中调用计时器的Start()方法以使其再次运行。或者使用周期为0的System.Threading.Timer。这是一个全能的更好的计时器,它不会在没有诊断的情况下吞下异常,就像System.Timers.Timer那样。
答案 1 :(得分:1)
也许我错过了什么,但你为什么不在计时器上禁用AutoReset(假设你使用的是System.Timers.Timer-你没有指定)?对你的Elapsed处理程序impl进行try / finally,以确保在完成后始终调用Start()。这样,在Elapsed处理程序完成之前,您的计时器不会再次启动。