首页 > 代码库 > .NET System.Timers.Timer的原理和使用(开发定时执行程序)
.NET System.Timers.Timer的原理和使用(开发定时执行程序)
概述(来自MSDN)
Timer 组件是基于服务器的计时器,它使您能够指定在应用程序中引发Elapsed 事件的周期性间隔。然后可以操控此事件以提供定期处理。例如,假设您有一台关键性服务器,必须每周7 天、每天24 小时都保持运行。可以创建一个使用Timer 的服务,以定期检查服务器并确保系统开启并在运行。如果系统不响应,则该服务可以尝试重新启动服务器或通知管理员。
基于服务器的Timer 是为在多线程环境中用于辅助线程而设计的。服务器计时器可以在线程间移动来处理引发的Elapsed 事件,这样就可以比Windows 计时器更精确地按时引发事件。
基于Interval 属性的值,Timer 组件引发Elapsed 事件。可以处理该事件以执行所需的处理。例如,假设您有一个联机销售应用程序,它不断向数据库发送销售订单。编译发货指令的服务分批处理订单,而不是分别处理每个订单。可以使用Timer 每30 分钟启动一次批处理。
注意
当AutoReset设置为false时,Timer只在第一个Interval过后引发一次Elapsed事件。若要保持以Interval时间间隔引发Elapsed 事件,请将AutoReset设置为true。
Elapsed事件在ThreadPool线程上引发。如果Elapsed事件的处理时间比Interval长,在另一个hreadPool线程上将会再次引发此事件。因此,事件处理程序应当是可重入的。
注意
在一个线程调用Stop 方法或将Enabled 属性设置为false 的同时,可在另一个线程上运行事件处理方法。这可能导致在计时器停止之后引发Elapsed 事件。Stop 方法的示例代码演示了一种避免此争用条件的方法。
如果和用户界面元素(如窗体或控件)一起使用Timer,请将包含有Timer 的窗体或控件赋值给SynchronizingObject 属性,以便将此事件封送到用户界面线程中。Timer 在运行时是不可见的。
几点说明
1 private System.Timers.Timer _TestTimerEvent= new Timer();
1
1、默认的周期是0.1秒执行一次;
2、AutoReset的初始值为true.
3、它的timer机制和System.Threading.Timer 原理是一样的。
4、每次周期(Timer)运行一次会新起一个线程。
5、如果Elapsed事件的处理时间比Interval长,它每个周期执行都会新起一个线程,这个线程的执行时间不受interval的限定,可以比interval长,因为一个新周期执行,又会新起一个线程,Timer起的线程周期就是事件处理时间。
我们来看它的实现代码.(.net framework 提供的).
001 //------------------------------------------------------------------------------
002 // <copyright file="Timer.cs" company="Microsoft">
003 // Copyright (c) Microsoft Corporation. All rights reserved.
004 // </copyright>
005 //-----------------------------------------------------------------------------
006
007 namespace System.Timers {
008
009 using System.Runtime.InteropServices;
010 using System.Security;
011 using System.Security.Permissions;
012 using System.Threading;
013 using System.ComponentModel;
014 using System.ComponentModel.Design;
015 using System;
016 using Microsoft.Win32;
017 using Microsoft.Win32.SafeHandles;
018
019 /// <devdoc>
020 /// <para>Handles recurring events in an application.</para>
021 /// </devdoc>
022 [
023 DefaultProperty("Interval"),
024 DefaultEvent("Elapsed"),
025 HostProtection(Synchronization=true, ExternalThreading=true)
026 ]
027 public class Timer : Component, ISupportInitialize {
028 private double interval;
029 private bool enabled;
030 private bool initializing;
031 private bool delayedEnable;
032 private ElapsedEventHandler onIntervalElapsed;
033 private bool autoReset;
034 private ISynchronizeInvoke synchronizingObject;
035 private bool disposed;
036 private System.Threading.Timer timer;
037 private TimerCallback callback;
038 private Object cookie;
039
040 /// <devdoc>
041 /// <para>Initializes a new instance of the <see cref=‘System.Timers.Timer‘/> class, with the properties
042 /// set to initial values.</para>
043 /// </devdoc>
044 public Timer()
045 : base() {
046 interval = 100;
047 enabled = false;
048 autoReset = true;
049 initializing = false;
050 delayedEnable = false;
051 callback = new TimerCallback(this.MyTimerCallback);
052 }
053
054 /// <devdoc>
055 /// <para>
056 /// Initializes a new instance of the <see cref=‘System.Timers.Timer‘/> class, setting the <see cref=‘System.Timers.Timer.Interval‘/> property to the specified period.
057 /// </para>
058 /// </devdoc>
059 public Timer(double interval)
060 : this() {
061 if (interval <= 0)
062 throw new ArgumentException(SR.GetString(SR.InvalidParameter, "interval", interval));
063
064 int i = (int)Math.Ceiling(interval);
065 if( i < 0) {
066 throw new ArgumentException(SR.GetString(SR.InvalidParameter, "interval", interval));
067 }
068
069 this.interval = interval;
070 }
071
072 /// <devdoc>
073 /// <para>Gets or sets a value indicating whether the Timer raises the Tick event each time the specified
074 /// Interval has elapsed,
075 /// when Enabled is set to true.</para>
076 /// </devdoc>
077 [Category("Behavior"), TimersDescription(SR.TimerAutoReset), DefaultValue(true)]
078 public bool AutoReset {
079 get {
080 return this.autoReset;
081 }
082
083 set {
084 if (DesignMode)
085 this.autoReset = value;
086 else if (this.autoReset != value) {
087 this.autoReset = value;
088 if( timer != null) {
089 UpdateTimer();
090 }
091 }
092 }
093 }
094
095 /// <devdoc>
096 /// <para>Gets or sets a value indicating whether the <see cref=‘System.Timers.Timer‘/>
097 /// is able
098 /// to raise events at a defined interval.</para>
099 /// </devdoc>
100 //[....] - The default value by design is false, don‘t change it.
101 [Category("Behavior"), TimersDescription(SR.TimerEnabled), DefaultValue(false)]
102 public bool Enabled {
103 get {
104 return this.enabled;
105 }
106
107 set {
108 if (DesignMode) {
109 this.delayedEnable = value;
110 this.enabled = value;
111 }
112 else if (initializing)
113 this.delayedEnable = value;
114 else if (enabled != value) {
115 if (!value) {
116 if( timer != null) {
117 cookie = null;
118 timer.Dispose();
119 timer = null;
120 }
121 enabled = value;
122 }
123 else {
124 enabled = value;
125 if( timer == null) {
126 if (disposed) {
127 throw new ObjectDisposedException(GetType().Name);
128 }
129
130 int i = (int)Math.Ceiling(interval);
131 cookie = new Object();
132 timer = new System.Threading.Timer(callback, cookie, i, autoReset? i:Timeout.Infinite);
133 }
134 else {
135 UpdateTimer();
136 }
137 }
138
139 }
140 }
141 }
142
143
144 private void UpdateTimer() {
145 int i = (int)Math.Ceiling(interval);
146 timer.Change(i, autoReset? i :Timeout.Infinite );
147 }
148
149 /// <devdoc>
150 /// <para>Gets or
151 /// sets the interval on which
152 /// to raise events.</para>
153 /// </devdoc>
154 [Category("Behavior"), TimersDescription(SR.TimerInterval), DefaultValue(100d), RecommendedAsConfigurable(true)]
155 public double Interval {
156 get {
157 return this.interval;
158 }
159
160 set {
161 if (value <= 0)
162 throw new ArgumentException(SR.GetString(SR.TimerInvalidInterval, value, 0));
163
164 interval = value;
165 if (timer != null) {
166 UpdateTimer();
167 }
168 }
169 }
170
171
172 /// <devdoc>
173 /// <para>Occurs when the <see cref=‘System.Timers.Timer.Interval‘/> has
174 /// elapsed.</para>
175 /// </devdoc>
176 [Category("Behavior"), TimersDescription(SR.TimerIntervalElapsed)]
177 public event ElapsedEventHandler Elapsed {
178 add {
179 onIntervalElapsed += value;
180 }
181 remove {
182 onIntervalElapsed -= value;
183 }
184 }
185
186 /// <devdoc>
187 /// <para>
188 /// Sets the enable property in design mode to true by default.
189 /// </para>
190 /// </devdoc>
191 /// <internalonly/>
192 public override ISite Site {
193 set {
194 base.Site = value;
195 if (this.DesignMode)
196 this.enabled= true;
197 }
198
199 get {
200 return base.Site;
201 }
202 }
203
204
205 /// <devdoc>
206 /// <para>Gets or sets the object used to marshal event-handler calls that are issued when
207 /// an interval has elapsed.</para>
208 /// </devdoc>
209 [
210 Browsable(false),
211 DefaultValue(null),
212 TimersDescription(SR.TimerSynchronizingObject)
213 ]
214 public ISynchronizeInvoke SynchronizingObject {
215 get {
216 if (this.synchronizingObject == null && DesignMode) {
217 IDesignerHost host = (IDesignerHost)GetService(typeof(IDesignerHost));
218 if (host != null) {
219 object baseComponent = host.RootComponent;
220 if (baseComponent != null && baseComponent is ISynchronizeInvoke)
221 this.synchronizingObject = (ISynchronizeInvoke)baseComponent;
222 }
223 }
224
225 return this.synchronizingObject;
226 }
227
228 set {
229 this.synchronizingObject = value;
230 }
231 }
232
233 /// <devdoc>
234 /// <para>
235 /// Notifies
236 /// the object that initialization is beginning and tells it to stand by.
237 /// </para>
238 /// </devdoc>
239 public void BeginInit() {
240 this.Close();
241 this.initializing = true;
242 }
243
244 /// <devdoc>
245 /// <para>Disposes of the resources (other than memory) used by
246 /// the <see cref=‘System.Timers.Timer‘/>.</para>
247 /// </devdoc>
248 public void Close() {
249 initializing = false;
250 delayedEnable = false;
251 enabled = false;
252
253 if (timer != null ) {
254 timer.Dispose();
255 timer = null;
256 }
257 }
258
259 /// <internalonly/>
260 /// <devdoc>
261 /// </devdoc>
262 protected override void Dispose(bool disposing) {
263 Close();
264 this.disposed = true;
265 base.Dispose(disposing);
266 }
267
268 /// <devdoc>
269 /// <para>
270 /// Notifies the object that initialization is complete.
271 /// </para>
272 /// </devdoc>
273 public void EndInit() {
274 this.initializing = false;
275 this.Enabled = this.delayedEnable;
276 }
277
278 /// <devdoc>
279 /// <para>Starts the timing by setting <see cref=‘System.Timers.Timer.Enabled‘/> to <see langword=‘true‘/>.</para>
280 /// </devdoc>
281 public void Start() {
282 Enabled = true;
283 }
284
285 /// <devdoc>
286 /// <para>
287 /// Stops the timing by setting <see cref=‘System.Timers.Timer.Enabled‘/> to <see langword=‘false‘/>.
288 /// </para>
289 /// </devdoc>
290 public void Stop() {
291 Enabled = false;
292 }
293
294 private void MyTimerCallback(object state) {
295 // System.Threading.Timer will not cancel the work item queued before the timer is stopped.
296 // We don‘t want to handle the callback after a timer is stopped.
297 if( state != cookie) {
298 return;
299 }
300
301 if (!this.autoReset) {
302 enabled = false;
303 }
304
305 FILE_TIME filetime = new FILE_TIME();
306 GetSystemTimeAsFileTime(ref filetime);
307 ElapsedEventArgs elapsedEventArgs = new ElapsedEventArgs(filetime.ftTimeLow, filetime.ftTimeHigh);
308 try {
309 // To avoid ---- between remove handler and raising the event
310 ElapsedEventHandler intervalElapsed = this.onIntervalElapsed;
311 if (intervalElapsed != null) {
312 if (this.SynchronizingObject != null && this.SynchronizingObject.InvokeRequired)
313 this.SynchronizingObject.BeginInvoke(intervalElapsed, new object[]{this, elapsedEventArgs});
314 else
315 intervalElapsed(this, elapsedEventArgs);
316 }
317 }
318 catch {
319 }
320 }
321
322 [StructLayout(LayoutKind.Sequential)]
323 internal struct FILE_TIME {
324 internal int ftTimeLow;
325 internal int ftTimeHigh;
326 }
327
328 [DllImport(ExternDll.Kernel32), SuppressUnmanagedCodeSecurityAttribute()]
329 internal static extern void GetSystemTimeAsFileTime(ref FILE_TIME lpSystemTimeAsFileTime);
330 }
331 }
332
333
334 // File provided for Reference Use Only by Microsoft Corporation (c) 2007.
在初始化的时候它的代码实现是这样的.
1 public Timer()
2 : base() {
3 interval = 100;
4 enabled = false;
5 autoReset = true;
6 initializing = false;
7 delayedEnable = false;
8 callback = new TimerCallback(this.MyTimerCallback);
9 }
而如果你是这样的话
01 public Timer(double interval)
02 : this() {
03 if (interval <= 0)
04 throw new ArgumentException(SR.GetString(SR.InvalidParameter, "interval", interval));
05
06 int i = (int)Math.Ceiling(interval);
07 if( i < 0) {
08 throw new ArgumentException(SR.GetString(SR.InvalidParameter, "interval", interval));
09 }
10
11 this.interval = interval;
12 }
你就需要再设置下AutoReset = True;
我们加载事件的Elapsed的代码实现是这样的.
01 /// <devdoc>
02 /// <para>Occurs when the <see cref=‘System.Timers.Timer.Interval‘/> has
03 /// elapsed.</para>
04 /// </devdoc>
05 [Category("Behavior"), TimersDescription(SR.TimerIntervalElapsed)]
06 public event ElapsedEventHandler Elapsed {
07 add {
08 onIntervalElapsed += value;
09 }
10 remove {
11 onIntervalElapsed -= value;
12 }
13 }
对它的基本原理有一定了解后,我们开始写一个简单的实现程序。
01 using System;
02 using System.Collections.Generic;
03 using System.Linq;
04 using System.Text;
05 using System.Threading;
06 using Timer = System.Timers.Timer;
07 using System.Timers;
08
09 namespace TestMultipleThread
10 {
11
12 public class ThreadWork
13 {
14 private System.Timers.Timer _TestTimerEvent;
15
16 public void StartWork()
17 {
18 _TestTimerEvent = new Timer();
19 _TestTimerEvent.Elapsed += Sum;
20 _TestTimerEvent.Start();
21 }
22
23 public static object lockobject = new object();
24
25
26 private void Sum(object sender, ElapsedEventArgs e)
27 {
28 Console.WriteLine(string.Format("this is thread ID {0} execute", Thread.CurrentThread.ManagedThreadId));
29 for (int i = 0; i < 10000; i++)
30 {
31 Thread.Sleep(10);
32 }
33 }
34 }
35
36 class Program
37 {
38 public static void Main()
39 {
40 ThreadWork threadWork = new ThreadWork();
41 ThreadStart myThreadDelegate = new ThreadStart(threadWork.StartWork);
42 Thread myThread = new Thread(myThreadDelegate);
43 myThread.Start();
44
45 Thread.Sleep(1000000);
46 }
47 }
48 }
查看的运行结果是:
我们看下执行的线程数有多少
能说明的一个问题就是在timer每次执行时都会新起一个线程来执行。
.NET System.Timers.Timer的原理和使用(开发定时执行程序)