首页 > 代码库 > .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 }

查看的运行结果是:

image

我们看下执行的线程数有多少

image

能说明的一个问题就是在timer每次执行时都会新起一个线程来执行。

.NET System.Timers.Timer的原理和使用(开发定时执行程序)