DispatchTimer - 如果上一个刻度仍在运行,则防止触发刻度事件
在 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 不会触发另一个事件?有哪些选择以及最好的方法是什么?使用锁?
In a Silverlight app, I have a block of code that has to run every 500ms. I am planning o use a DispatcherTimer to achieve this (see code below).
DispatcherTimer dt = new DispatcherTimer();
dt.Interval = new TimeSpan(0, 0, 0, 0, 500); // 500 Milliseconds
dt.Tick += new EventHandler(dt_Tick);
dt.Start();
However, it may happen that the block of code takes longer than 500ms to execute (the block of code does some webservice calls). How do I make sure that if a call is currently in progress, the DispatcherTimer doesn't trigger another event? What are the options and what is the best way? Using locks?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
DispatcherTimer
仅在调度程序线程上运行 - 因此您不可能同时运行两个处理程序。当然,它们可能会排队并直接一个接一个地运行 - 您应该检查一下。但是,无论如何,您都不应该在 DispatcherTimer 中进行 Web 服务调用。在后台线程中执行此操作,否则您在等待 Web 服务的过程中会一直阻塞 UI 更新。基本上,您不应该在 UI 线程中执行任何长时间运行的工作。使用各种其他计时器之一(例如
System.Timers .Timer
)定期在线程池线程上执行工作,并在获得需要在 UI 上显示的数据时使用调度程序回调 UI 线程。当然,现在您遇到了新型计时器在多个线程上同时触发多次的潜在问题。避免这种情况的一种方法是将 AutoReset 属性设置为 false,然后将下一个计时器滴答安排在当前计时器滴答结束时。
The
DispatcherTimer
only runs on the dispatcher thread - so there's no way you could have two handlers running at the same time. It's possible they'll be queued up and run one directly after another, of course - you should check.However, you shouldn't be making a web service call in a
DispatcherTimer
anyway. Do it in a background thread, otherwise you're blocking the UI for updating all the time that you're waiting for the web service. Basically you shouldn't do any long-running work in the UI thread. Use one of the various other timers (e.g.System.Timers.Timer
) to regularly perform work on a thread pool thread and use the dispatcher to call back to the UI thread when you've got some data which needs to be displayed on the UI.Of course, now you've got the potential problem of the new kind of timer firing multiple times concurrently, on multiple threads. One option to avoid this is to set the
AutoReset
property to false, and just schedule the next timer tick at the end of the current one.我想说的是,如果时间太长,你就跳过一个刻度,否则你会因为锁而得到一个巨大的队列。
所以在事件处理程序中说:
I would say you skip a tick if it takes too long, otherwise you will get a huge queue because of the lock.
So in the eventhandler say:
为了使事件成功运行,而无需再次从 DispatcherTimer 调用,在进入
dt_Tick
事件后并在上一个刻度完成后stop
调度程序计时器tick 事件再次调用start
,这将初始化 DispatcherTimer 的 IsEnabled 再次设置为 true。In order make the event run successfull without getting a call from your DispatcherTimer again with in the previous tick completes
stop
the dispatcher timer after entering in todt_Tick
event and at the end of the tick event call thestart
again which will initializes the IsEnabled of DispatcherTimer again to true.我不知道 DispatchTimer 是否有任何聪明的方法来做到这一点,但在这种情况下我会做的不是尝试让计时器不触发事件,而是让事件在尚未完成前一个事件时不执行任何操作跑步。
您可以通过在事件处理程序的开头获取锁来使用锁来完成此操作。如果锁不可用,则退出该函数(它已经在运行),如果您获得锁,则执行工作,然后在完成工作后释放锁。
您想要的方法是 Monitor.TryEnter 和您需要确保像使用锁一样正确地进行错误捕获。
I don't know if DispatchTimer has any clever way to do this but what I would do in this situation is not to try to get the timer to not fire the event but to get the event to do nothing if it has not finished the previous run.
You can use locks to do this by getting a lock at the beginning of your event handler. If the lock is not available then exit the function (its already running) if you get the lock do the work and then once you've finished the work release the lock.
The method you want is Monitor.TryEnter and you'll want to make sure that you do your error trapping correctly as with any use of locks.