zoukankan      html  css  js  c++  java
  • .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 在运行时是不可见的

     

    几点说明

     private System.Timers.Timer _TestTimerEvent= new Timer();
     

    1、默认的周期是0.1秒执行一次;

    2、AutoReset的初始值为true.

    3、它的timer机制和System.Threading.Timer 原理是一样的。

    4、每次周期(Timer)运行一次会新起一个线程。

    5、如果Elapsed事件的处理时间比Interval长,它每个周期执行都会新起一个线程,这个线程的执行时间不受interval的限定,可以比interval长,因为一个新周期执行,又会新起一个线程,Timer起的线程周期就是事件处理时间。

    我们来看它的实现代码.(.net framework 提供的).

    //------------------------------------------------------------------------------ 
    // <copyright file="Timer.cs" company="Microsoft">
    //     Copyright (c) Microsoft Corporation.  All rights reserved.
    // </copyright>
    //----------------------------------------------------------------------------- 
    
    namespace System.Timers { 
     
        using System.Runtime.InteropServices;
        using System.Security; 
        using System.Security.Permissions;
        using System.Threading;
        using System.ComponentModel;
        using System.ComponentModel.Design; 
        using System;
        using Microsoft.Win32; 
        using Microsoft.Win32.SafeHandles; 
    
        /// <devdoc> 
        ///    <para>Handles recurring events in an application.</para>
        /// </devdoc>
        [
        DefaultProperty("Interval"), 
        DefaultEvent("Elapsed"),
        HostProtection(Synchronization=true, ExternalThreading=true) 
        ] 
        public class Timer : Component, ISupportInitialize {
            private double interval; 
            private bool  enabled;
            private bool initializing;
            private bool delayedEnable;
            private ElapsedEventHandler onIntervalElapsed; 
            private bool autoReset;
            private ISynchronizeInvoke synchronizingObject; 
            private bool disposed; 
            private System.Threading.Timer timer;
            private TimerCallback callback; 
            private Object cookie;
    
            /// <devdoc>
            /// <para>Initializes a new instance of the <see cref='System.Timers.Timer'/> class, with the properties 
            ///    set to initial values.</para>
            /// </devdoc> 
            public Timer() 
            : base() {
                interval = 100; 
                enabled = false;
                autoReset = true;
                initializing = false;
                delayedEnable = false; 
                callback = new TimerCallback(this.MyTimerCallback);
            } 
     
            /// <devdoc>
            ///    <para> 
            ///       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.
            ///    </para>
            /// </devdoc>
            public Timer(double interval) 
            : this() {
                if (interval <= 0) 
                    throw new ArgumentException(SR.GetString(SR.InvalidParameter, "interval", interval)); 
    
                int i = (int)Math.Ceiling(interval); 
                if( i < 0) {
                    throw new ArgumentException(SR.GetString(SR.InvalidParameter, "interval", interval));
                }
     
                this.interval = interval;
            } 
     
            /// <devdoc>
            /// <para>Gets or sets a value indicating whether the Timer raises the Tick event each time the specified 
            /// Interval has elapsed,
            ///    when Enabled is set to true.</para>
            /// </devdoc>
            [Category("Behavior"),  TimersDescription(SR.TimerAutoReset), DefaultValue(true)] 
            public bool AutoReset {
                get { 
                    return this.autoReset; 
                }
     
                set {
                    if (DesignMode)
                         this.autoReset = value;
                    else if (this.autoReset != value) { 
                         this.autoReset = value;
                        if( timer != null) { 
                             UpdateTimer(); 
                        }
                    } 
                }
            }
    
            /// <devdoc> 
            /// <para>Gets or sets a value indicating whether the <see cref='System.Timers.Timer'/>
            /// is able 
            /// to raise events at a defined interval.</para> 
            /// </devdoc>
            //[....] - The default value by design is false, don't change it. 
            [Category("Behavior"), TimersDescription(SR.TimerEnabled), DefaultValue(false)]
            public bool Enabled {
                get {
                    return this.enabled; 
                }
     
                set { 
                    if (DesignMode) {
                        this.delayedEnable = value; 
                        this.enabled = value;
                    }
                    else if (initializing)
                        this.delayedEnable = value; 
                    else if (enabled != value) {
                        if (!value) { 
                            if( timer != null) { 
                                cookie = null;
                                timer.Dispose(); 
                                timer = null;
                            }
                            enabled = value;
                        } 
                        else {
                            enabled = value; 
                            if( timer == null) { 
                                if (disposed) {
                                    throw new ObjectDisposedException(GetType().Name); 
                                }
    
                                int i = (int)Math.Ceiling(interval);
                                cookie = new Object(); 
                                timer = new System.Threading.Timer(callback, cookie, i, autoReset? i:Timeout.Infinite);
                            } 
                            else { 
                                UpdateTimer();
                            } 
                        }
    
                    }
              } 
            }
     
     
            private void UpdateTimer() {
                int i = (int)Math.Ceiling(interval); 
                timer.Change(i, autoReset? i :Timeout.Infinite );
            }
    
            /// <devdoc> 
            ///    <para>Gets or
            ///       sets the interval on which 
            ///       to raise events.</para> 
            /// </devdoc>
            [Category("Behavior"), TimersDescription(SR.TimerInterval), DefaultValue(100d), RecommendedAsConfigurable(true)] 
            public double Interval {
                get {
                    return this.interval;
                } 
    
                set { 
                    if (value <= 0) 
                        throw new ArgumentException(SR.GetString(SR.TimerInvalidInterval, value, 0));
     
                    interval = value;
                    if (timer != null) {
                        UpdateTimer();
                    } 
                }
            } 
     
    
            /// <devdoc> 
            /// <para>Occurs when the <see cref='System.Timers.Timer.Interval'/> has
            ///    elapsed.</para>
            /// </devdoc>
            [Category("Behavior"), TimersDescription(SR.TimerIntervalElapsed)] 
            public event ElapsedEventHandler Elapsed {
                add { 
                    onIntervalElapsed += value; 
                }
                remove { 
                    onIntervalElapsed -= value;
                }
            }
     
            /// <devdoc>
            ///    <para> 
            ///       Sets the enable property in design mode to true by default. 
            ///    </para>
            /// </devdoc> 
            /// <internalonly/>
            public override ISite Site {
                set {
                    base.Site = value; 
                    if (this.DesignMode)
                        this.enabled= true; 
                } 
    
                get { 
                    return base.Site;
                }
            }
     
    
            /// <devdoc> 
            ///    <para>Gets or sets the object used to marshal event-handler calls that are issued when 
            ///       an interval has elapsed.</para>
            /// </devdoc> 
            [
            Browsable(false),
            DefaultValue(null),
            TimersDescription(SR.TimerSynchronizingObject) 
            ]
            public ISynchronizeInvoke SynchronizingObject { 
                get { 
                    if (this.synchronizingObject == null && DesignMode) {
                        IDesignerHost host = (IDesignerHost)GetService(typeof(IDesignerHost)); 
                        if (host != null) {
                            object baseComponent = host.RootComponent;
                            if (baseComponent != null && baseComponent is ISynchronizeInvoke)
                                this.synchronizingObject = (ISynchronizeInvoke)baseComponent; 
                        }
                    } 
     
                    return this.synchronizingObject;
                } 
    
                set {
                    this.synchronizingObject = value;
                } 
            }
     
            /// <devdoc> 
            ///    <para>
            ///       Notifies 
            ///       the object that initialization is beginning and tells it to stand by.
            ///    </para>
            /// </devdoc>
            public void BeginInit() { 
                this.Close();
                this.initializing = true; 
            } 
    
            /// <devdoc> 
            ///    <para>Disposes of the resources (other than memory) used by
            ///       the <see cref='System.Timers.Timer'/>.</para>
            /// </devdoc>
            public void Close() { 
                initializing = false;
                delayedEnable = false; 
                enabled = false; 
    
                if (timer != null ) { 
                    timer.Dispose();
                    timer = null;
                }
            } 
    
            /// <internalonly/> 
            /// <devdoc> 
            /// </devdoc>
            protected override void Dispose(bool disposing) { 
                Close();
                this.disposed = true;
                base.Dispose(disposing);
            } 
    
            /// <devdoc> 
            ///    <para> 
            ///       Notifies the object that initialization is complete.
            ///    </para> 
            /// </devdoc>
            public void EndInit() {
                this.initializing = false;
                this.Enabled = this.delayedEnable; 
            }
     
            /// <devdoc> 
            /// <para>Starts the timing by setting <see cref='System.Timers.Timer.Enabled'/> to <see langword='true'/>.</para>
            /// </devdoc> 
            public void Start() {
                Enabled = true;
            }
     
            /// <devdoc>
            ///    <para> 
            ///       Stops the timing by setting <see cref='System.Timers.Timer.Enabled'/> to <see langword='false'/>. 
            ///    </para>
            /// </devdoc> 
            public void Stop() {
                Enabled = false;
            }
     
            private void MyTimerCallback(object state) {
                // System.Threading.Timer will not cancel the work item queued before the timer is stopped. 
                // We don't want to handle the callback after a timer is stopped. 
                if( state != cookie) {
                    return; 
                }
    
                if (!this.autoReset) {
                    enabled = false; 
                }
     
                FILE_TIME filetime = new FILE_TIME(); 
                GetSystemTimeAsFileTime(ref filetime);
                ElapsedEventArgs elapsedEventArgs = new ElapsedEventArgs(filetime.ftTimeLow, filetime.ftTimeHigh); 
                try {
                    // To avoid ---- between remove handler and raising the event
                    ElapsedEventHandler intervalElapsed = this.onIntervalElapsed;
                    if (intervalElapsed != null) { 
                        if (this.SynchronizingObject != null && this.SynchronizingObject.InvokeRequired)
                            this.SynchronizingObject.BeginInvoke(intervalElapsed, new object[]{this, elapsedEventArgs}); 
                        else 
                           intervalElapsed(this,  elapsedEventArgs);
                    } 
                }
                catch {
                }
            } 
    
            [StructLayout(LayoutKind.Sequential)] 
            internal struct FILE_TIME { 
                internal int ftTimeLow;
                internal int ftTimeHigh; 
            }
    
            [DllImport(ExternDll.Kernel32), SuppressUnmanagedCodeSecurityAttribute()]
            internal static extern void GetSystemTimeAsFileTime(ref FILE_TIME lpSystemTimeAsFileTime);		 
        }
    } 
     
    
    // File provided for Reference Use Only by Microsoft Corporation (c) 2007.

    在初始化的时候它的代码实现是这样的.

            public Timer() 
            : base() {
                interval = 100; 
                enabled = false;
                autoReset = true;
                initializing = false;
                delayedEnable = false; 
                callback = new TimerCallback(this.MyTimerCallback);
            } 

    而如果你是这样的话

     public Timer(double interval) 
            : this() {
                if (interval <= 0) 
                    throw new ArgumentException(SR.GetString(SR.InvalidParameter, "interval", interval)); 
    
                int i = (int)Math.Ceiling(interval); 
                if( i < 0) {
                    throw new ArgumentException(SR.GetString(SR.InvalidParameter, "interval", interval));
                }
     
                this.interval = interval;
            } 

    你就需要再设置下AutoReset = True;

    我们加载事件的Elapsed的代码实现是这样的.

            /// <devdoc> 
            /// <para>Occurs when the <see cref='System.Timers.Timer.Interval'/> has
            ///    elapsed.</para>
            /// </devdoc>
            [Category("Behavior"), TimersDescription(SR.TimerIntervalElapsed)] 
            public event ElapsedEventHandler Elapsed {
                add { 
                    onIntervalElapsed += value; 
                }
                remove { 
                    onIntervalElapsed -= value;
                }
            }

    对它的基本原理有一定了解后,我们开始写一个简单的实现程序。

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading;
    using Timer = System.Timers.Timer;
    using System.Timers;
    
    namespace TestMultipleThread
    {
    
        public class ThreadWork
        {
            private System.Timers.Timer _TestTimerEvent;
    
            public void StartWork()
            {
                _TestTimerEvent = new Timer();
                _TestTimerEvent.Elapsed += Sum;
                _TestTimerEvent.Start();
            }
    
            public static object lockobject = new object();
    
    
            private void Sum(object sender, ElapsedEventArgs e)
            {
                Console.WriteLine(string.Format("this is thread ID {0}  execute", Thread.CurrentThread.ManagedThreadId));
                for (int i = 0; i < 10000; i++)
                {
                    Thread.Sleep(10);
                }
            }
        }
    
        class Program
        {
            public static void Main()
            {
                ThreadWork threadWork = new ThreadWork();
                ThreadStart myThreadDelegate = new ThreadStart(threadWork.StartWork);
                Thread myThread = new Thread(myThreadDelegate);
                myThread.Start();
    
                Thread.Sleep(1000000);
            }
        }
    }

    查看的运行结果是:

    image

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

    image

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

    作者:spring yang

    出处:http://www.cnblogs.com/springyangwc/

    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

  • 相关阅读:
    教师节快乐!
    来自学长同学分享的学习方法
    刘奕佳: 我的职校新生活 | 班级日常分享
    19级:班级日常分享 | 一天一瞬间
    珍惜、珍爱!
    19级:班级日常分享 | 一天一瞬间
    204787 ,194787 |0001 1131 0001 4226 7035 ![2480 ]
    1-N的自然数中,少了一个,找出这个数 小强斋
    获取某一天之前或者之后多少天的日期 小强斋
    获取某一天之前或者之后多少天的日期 小强斋
  • 原文地址:https://www.cnblogs.com/springyangwc/p/2205733.html
Copyright © 2011-2022 走看看