喜欢VB.NET朋友一定会很喜欢研究定时器方面的问题吧。本人就很喜欢,在网上我收集了很多东西,在这个就VB.NET定时器事件重入的问题来和大家一起探讨一下。不论在客户端应用程序还是服务器组件(包括窗口服务)定时器通常扮演一个重要的角色。写一个高效的定时器驱动型可管理代码要求对程序流程有一个清晰的理解及掌握.NET线程模型的精妙之处。.NET框架类库提供了三种不同的定时器类:System.Windows.Forms.Timer, System.Timers.Timer, 和System.Threading.Timer。每个类为不同的场合进行设计和优化。本文章将研究这三个类并让你理解如何及何时应该使用哪一个类。
VB.NET定时器事件处理重入
当和异步定时器事件打交道时,如由System.Timers.Timer和System.Threading.Timer产生的定时器事件,有另外一个细微之处你需要考虑。问题就是必须处理代码重入。如果你的定时器事件处理函数代码执行时间比你的定时器引发定时器事件的时间间隔要长,你预先又没有采取必要的措施保护防止多线程访问你的对象和变量,你就会陷入调试的困境。看一下下面的代码片断:
- private int tickCounter = 0;
- private void tmrTimersTimer_Elapsed(object sender, System.Timers.ElapsedEventArgse)
- {
- System.Threading.Interlocked.Increment(ref tickCounter);
- Thread.Sleep(5000);
- MessageBox.Show(tickCounter.ToString());
- }
假设你的定时器间隔属性设置为1000毫秒,你也许会奇怪当***个信息框弹出时显示的值是5。这是因为在这5秒期间***个定时器事件正在睡眠,而定时器却在不同的工作者线程上继续产生时间消失事件。因此,在***个VB.NET定时器事件处理完成之前tickCounter变量被增加了5次。注意我使用了Interlocked.Increment方法以线程安全的方式增加tickCounter变量的值。也有其它方法可以这样做,但是Interlock.Increment是为这种操作而特别设计的。
解决这种问题的简单方法就是在你的事件处理函数代码块中暂时禁止定时器,接着再允许定时器,就像下面的代码:
- private void tmrTimersTimer_Elapsed(object sender, System.Timers.ElapsedEventArgse)
- {
- tmrTimers.Enabled = false;
- System.Threading.Interlocked.Increment(ref tickCounter);
- Thread.Sleep(5000);
- MessageBox.Show(tickCounter.ToString());
- tmrTimersTimer.Enabled = true;
- }
有了这段代码,消息框就会每5秒钟显示一次,就像你所期望的那样,tickCounter的值每次只增加1。另外一些可选的原始同步对象就是Monitor或mutex去确保所有将来的事件被排队直到当前的事件处理函数执行完成。
结论
当使用定时器类时有一点你要考虑的就是是否可以使用Windows调度器去定期的运行标准的可执行程序来更简单的解决问题。
【编辑推荐】