原文:http://msdn.microsoft.com/en-us/magazine/cc164015.aspx
原作者:Alex Calvo,is a Microsoft Certified Solutions Developer for .NET. When he's not reading, coding, or meditating, he's playing guitar. You can reach Alex at acalvo@hotmail.com.
注意: 有删节,仅译出其要点而已,也有自己添加的理解。
概要:
.NET Framework Class Library提供了三种不同的时钟类:System.Windows.Forms.Timer, System.Timers.Timer and System.Threading.Timer.各有不同的用武之地,本文旨在介绍其用法。
内容:
System.Windows.Forms.Timer
System.Timers.Timer
System.Threading.Timer
Dealing with Timer Event Reentrance
Conclusion
.NET Framework Class Library提供了三种不同的时钟类:System.Windows.Forms.Timer, System.Timers.Timer and System.Threading.Timer.各有不同的用武之地,本文旨在介绍其用法。
内容:
System.Windows.Forms.Timer
System.Timers.Timer
System.Threading.Timer
Dealing with Timer Event Reentrance
Conclusion
1)System.Windows.Forms.Timer
该类的最大特点是其与Winforms App同步,也就是说它的Tick events与UI在同一个线程执行。如果在响应函数执行耗时较多的话,则会出现UI无响应的情况。由此可见该类比较适用一些比较简单的情况。
原文链接中给出了一些演示示例,供读者来理解该类:
System.Windows.Forms.Timer Started @ 4:09:28 PM --> Timer Event 1 @ 4:09:29 PM on Thread: UIThread --> Timer Event 2 @ 4:09:30 PM on Thread: UIThread --> Timer Event 3 @ 4:09:31 PM on Thread: UIThread Sleeping for 5000 ms... --> Timer Event 4 @ 4:09:36 PM on Thread: UIThread System.Windows.Forms.Timer Stopped @ 4:09:37 PM
从上面代码可以看出,在其响应函数中休眠5000ms,这五秒钟的Timer Event就失效了。足见该Timer Event是在UI线程中执行的。此外要注意的是,尽管该类的Interval 最小可以为1ms,但是官方的文档说明该类大概只能精确到55ms.
下面代码是使用System.Windows.Forms.Timer class 示例:
System.Windows.Forms.Timer tmrWindowsFormsTimer = new System.Windows.Forms.Timer(); tmrWindowsFormsTimer.Interval = 1000; tmrWindowsFormsTimer.Tick += new EventHandler(tmrWindowsFormsTimer_Tick); tmrWindowsFormsTimer.Start(); ••• private void tmrWindowsFormsTimer_Tick(object sender, System.EventArgs e) { //Do something on the UI thread... }
2)System.Timers.Timer
.
Net Framework称该类是专为多线程环境而设计,且该类的对象是thread-safe的。不同于System.Windows.Forms.Timer,该类的Timer Event是在worker thread(来自线程池)中执行的,这就带来一个问题,如果你的响应函数中涉及到UI操作的话,那么一定要回调到UI线程执行。不过,System.Timers.Timer class提供了一种简单的方式来克服这种麻烦,它采用了“SynchronizingObject ”属性,若将UI forms 赋值于该属性,则SynchronizingObject.Begin.Invoke可让Timer Event在UI线程执行。考虑到UI的responsiveness,我觉得这个属性有些鸡肋。
演示代码:
使用示例:
3)System.Threading.Timer
该类可以说是三个类中最灵活的一个,但是其对象本身却并非thread-safe的。此外,其使用方式也与前二者不同:
演示代码:
4)Timer event重复进入问题
对于System.Timers.Timer class和System.Threading.Timer,其timer event异步执行的,还有一个问题需要注意。如果响应函数执行时间超过了Interval值,那么响应函数会被重复进入,那么在这里就特别需要注意变量的同步了。如果读者不想反复进入呢,那么可以参考如下示例:
5)总结
相关文章:
Windows Forms: Give Your .NET-Based Application a Fast and Responsive UI with Multiple Threads
背景信息:
Programming the Thread Pool in the .NET Framework: Using Timers
.NET Framework Class Library
演示代码:
System.Timers.Timer Started @ 5:15:01 PM --> Timer Event 1 @ 5:15:02 PM on Thread: WorkerThread --> Timer Event 2 @ 5:15:03 PM on Thread: WorkerThread --> Timer Event 3 @ 5:15:04 PM on Thread: WorkerThread Sleeping for 5000 ms... --> Timer Event 4 @ 5:15:05 PM on Thread: WorkerThread --> Timer Event 5 @ 5:15:06 PM on Thread: WorkerThread --> Timer Event 6 @ 5:15:07 PM on Thread: WorkerThread --> Timer Event 7 @ 5:15:08 PM on Thread: WorkerThread --> Timer Event 8 @ 5:15:09 PM on Thread: WorkerThread System.Timers.Timer Stopped @ 5:15:10 PM
这里有个问题需要注意,由于timer event是在独立线程中执行的,那么有可能用户已经调用stop函数了,仍会产生timer event事件。ElapsedEventArgs 中包含了一个“SignalTime ”属性,表示已经过去的时间,用户可以将这个时间与stop函数的调用时间相比,以决定是否继续执行响应函数。笔者在这里就遇到一个类似的问题,在窗体函数已经销毁后,仍在timer event响应函数中调用Invoke函数,导致了异常,通过该属性则可避免类似情况。System.Timers.Timer tmrTimersTimer = new System.Timers.Timer(); tmrTimersTimer.Interval = 1000; tmrTimersTimer.Elapsed += new ElapsedEventHandler(tmrTimersTimer_Elapsed); tmrTimersTimer.SynchronizingObject = this; //Synchronize with //the current form... tmrTimersTimer.Start(); ••• private void tmrTimersTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e) { // Do something on the UI thread (same thread the form was // created on)... // If we didn't set SynchronizingObject we would be on a // worker thread... }
3)System.Threading.Timer
该类可以说是三个类中最灵活的一个,但是其对象本身却并非thread-safe的。此外,其使用方式也与前二者不同:
public Timer(TimerCallback callback, object state, long dueTime, long period); public Timer(TimerCallback callback, object state, UInt32 dueTime, UInt32 period); public Timer(TimerCallback callback, object state, int dueTime, int period); public Timer(TimerCallback callback, object state, TimeSpan dueTime, TimeSpan period);
与 System.Timers.Timer class相比较, 该类并没有“SynchronizingObject ”这个属性,也就是说,若在响应函数中涉及UI操作,则需用户自己调用Invoke或者BeginInvoke。System.Threading.Timer Started @ 7:17:11 AM --> Timer Event 1 @ 7:17:12 AM on Thread: WorkerThread --> Timer Event 2 @ 7:17:13 AM on Thread: WorkerThread --> Timer Event 3 @ 7:17:14 AM on Thread: WorkerThread Sleeping for 5000 ms... --> Timer Event 4 @ 7:17:15 AM on Thread: WorkerThread --> Timer Event 5 @ 7:17:16 AM on Thread: WorkerThread --> Timer Event 6 @ 7:17:17 AM on Thread: WorkerThread --> Timer Event 7 @ 7:17:18 AM on Thread: WorkerThread --> Timer Event 8 @ 7:17:19 AM on Thread: WorkerThread System.Threading.Timer Stopped @ 7:17:20 AM
4)Timer event重复进入问题
对于System.Timers.Timer class和System.Threading.Timer,其timer event异步执行的,还有一个问题需要注意。如果响应函数执行时间超过了Interval值,那么响应函数会被重复进入,那么在这里就特别需要注意变量的同步了。如果读者不想反复进入呢,那么可以参考如下示例:
在响应函数中操作其Enabled属性。private void tmrTimersTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e) { tmrTimersTimer.Enabled = false; System.Threading.Interlocked.Increment(ref tickCounter); Thread.Sleep(5000); MessageBox.Show(tickCounter.ToString()); tmrTimersTimer.Enabled = true; }
5)总结
System.Windows.Forms | System.Timers | System.Threading | |
Timer event 所在线程 | UI thread | UI or worker thread | Worker thread |
对象是否thread safe? | No | Yes | No |
是否需要Windows Forms? | Yes | No | No |
Timer event 是否支持状态变量? | No | No | Yes |
初始timer event是否可被延迟? | No | No | Yes |
Class 是否支持继承? | Yes | Yes | No |
相关文章:
Windows Forms: Give Your .NET-Based Application a Fast and Responsive UI with Multiple Threads
背景信息:
Programming the Thread Pool in the .NET Framework: Using Timers
.NET Framework Class Library