5

在 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 不会触发另一个事件?有哪些选择,最好的方法是什么?使用锁?

4

4 回答 4

5

DispatcherTimer 唯一在调度程序线程上运行 - 所以你不可能同时运行两个处理程序。当然,它们可能会排队并直接运行 - 你应该检查一下。

但是,无论如何,您都不应该进行 Web 服务调用。DispatcherTimer在后台线程中执行此操作,否则您在等待 Web 服务的所有时间都会阻止 UI 进行更新。基本上你不应该在 UI 线程中做任何长时间运行的工作。使用各种其他计时器之一(例如System.Timers.Timer)定期在线程池线程上执行工作,并在您有一些需要在 UI 上显示的数据时使用调度程序回调 UI 线程。

当然,现在您遇到了新类型的计时器在多个线程上同时触发多次的潜在问题。避免这种情况的一种选择是将AutoReset属性设置为 false,并在当前计时器结束时安排下一个计时器滴答。

于 2011-10-18T13:22:56.573 回答
1

为了使事件成功运行而无需再次从您的 DispatcherTimer 中获得调用,stop在进入dt_Tick事件后完成调度程序计时器并在滴答事件结束时调用start再次将 DispatcherTimer 的IsEnabled初始化为 true .

于 2011-10-18T13:22:22.670 回答
1

如果时间太长,我会说你跳过一个滴答声,否则你会因为锁而得到一个巨大的队列。

所以在事件处理程序中说:

if(!busy) {
  busy = true;

  // some code which could take longer than 500 ms

  busy = false;
}
于 2011-10-18T13:20:24.137 回答
1

我不知道 DispatchTimer 是否有任何聪明的方法可以做到这一点,但在这种情况下我会做的不是试图让计时器不触发事件,而是让事件在之前没有完成的情况下什么都不做跑。

您可以通过在事件处理程序的开头获取锁来使用锁来执行此操作。如果锁不可用,则退出函数(它已经在运行)如果你得到锁做工作,然后一旦你完成工作释放锁。

您想要的方法是Monitor.TryEnter,您需要确保正确地执行错误捕获,就像使用任何锁一样。

于 2011-10-18T13:21:03.793 回答