• .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每次执行时都会新起一个线程来执行。

  • 相关阅读:
    Linux忘了root的密码怎么办
    缩略图的实现
    ASP.NET程序编写注意 (转载)
    太极拳
    Linux系统管理技巧大荟萃
    茶经(转载)
    datagrid的显示控制
    太极功
    Linux下硬盘分区详解
    Tomcat4.0中文问题简单解决方法
  • 原文地址:https://www.cnblogs.com/rr163/p/4123156.html
Copyright © 2020-2023  润新知