DispatchTimer – 如果上一个tick仍在运行,则阻止触发tick事件
在Silverlight应用程序中,我有一段代码必须每500毫秒运行一次。 我计划使用DispatcherTimer来实现这一点(参见下面的代码)。
DispatcherTimer dt = new DispatcherTimer(); dt.Interval = new TimeSpan(0, 0, 0, 0, 500); // 500 Milliseconds dt.Tick += new EventHandler(dt_Tick); dt.Start();
但是,可能会发生代码块执行时间超过500毫秒(代码块执行一些Web服务调用)。 如何确保当前正在进行呼叫时,DispatcherTimer不会触发另一个事件? 有哪些选择?什么是最好的方法? 使用锁?
DispatcherTimer
仅在调度程序线程上运行 – 因此您无法同时运行两个处理程序。 它们可能会排队等候并且直接运行一个,当然 – 你应该检查。
但是,您不应该在DispatcherTimer
进行Web服务调用。 在后台线程中执行此操作,否则您将阻止UI在您等待Web服务的所有时间进行更新。 基本上你不应该在UI线程中做任何长时间运行的工作。 使用其他各种计时器之一(例如System.Timers.Timer
)定期在线程池线程上执行工作,并在需要在UI上显示某些数据时使用调度程序回调UI线程。
当然,现在你已经遇到了多种线程同时多次同时触发的新型定时器的潜在问题。 避免这种情况的一个选项是将AutoReset
属性设置为false,并且只安排当前结束时的下一个计时器滴答。
如果花费太长时间,我会说你跳过一个勾号,否则你会因为锁而得到一个巨大的队列。
所以在事件处理程序中说:
if(!busy) { busy = true; // some code which could take longer than 500 ms busy = false; }
为了使事件成功运行而没有再次从DispatcherTimer调用,在上一个tick完成后,在输入到dt_Tick
事件后stop
调度程序计时器,并在tick事件结束start
再次调用start
,这将初始化DispatcherTimer的IsEnabled再次成真。
我不知道DispatchTimer是否有任何聪明的方法可以做到这一点,但在这种情况下我会做的不是试图让计时器不激活事件,而是让事件在没有完成之前的任何事情跑。
您可以通过在事件处理程序的开头获取锁来使用锁来执行此操作。 如果锁定不可用,则退出该function(已经运行),如果锁定完成工作,则完成工作后释放锁定。
你想要的方法是Monitor.TryEnter ,你要确保你正确地执行错误捕获,就像使用任何锁一样。