• .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、默认的周期是0.1秒执行一次;

    2、AutoReset的初始值为true.

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

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

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

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

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    17

    18

    19

    20

    21

    22

    23

    24

    25

    26

    27

    28

    29

    30

    31

    32

    33

    34

    35

    36

    37

    38

    39

    40

    41

    42

    43

    44

    45

    46

    47

    48

    49

    50

    51

    52

    53

    54

    55

    56

    57

    58

    59

    60

    61

    62

    63

    64

    65

    66

    67

    68

    69

    70

    71

    72

    73

    74

    75

    76

    77

    78

    79

    80

    81

    82

    83

    84

    85

    86

    87

    88

    89

    90

    91

    92

    93

    94

    95

    96

    97

    98

    99

    100

    101

    102

    103

    104

    105

    106

    107

    108

    109

    110

    111

    112

    113

    114

    115

    116

    117

    118

    119

    120

    121

    122

    123

    124

    125

    126

    127

    128

    129

    130

    131

    132

    133

    134

    135

    136

    137

    138

    139

    140

    141

    142

    143

    144

    145

    146

    147

    148

    149

    150

    151

    152

    153

    154

    155

    156

    157

    158

    159

    160

    161

    162

    163

    164

    165

    166

    167

    168

    169

    170

    171

    172

    173

    174

    175

    176

    177

    178

    179

    180

    181

    182

    183

    184

    185

    186

    187

    188

    189

    190

    191

    192

    193

    194

    195

    196

    197

    198

    199

    200

    201

    202

    203

    204

    205

    206

    207

    208

    209

    210

    211

    212

    213

    214

    215

    216

    217

    218

    219

    220

    221

    222

    223

    224

    225

    226

    227

    228

    229

    230

    231

    232

    233

    234

    235

    236

    237

    238

    239

    240

    241

    242

    243

    244

    245

    246

    247

    248

    249

    250

    251

    252

    253

    254

    255

    256

    257

    258

    259

    260

    261

    262

    263

    264

    265

    266

    267

    268

    269

    270

    271

    272

    273

    274

    275

    276

    277

    278

    279

    280

    281

    282

    283

    284

    285

    286

    287

    288

    289

    290

    291

    292

    293

    294

    295

    296

    297

    298

    299

    300

    301

    302

    303

    304

    305

    306

    307

    308

    309

    310

    311

    312

    313

    314

    315

    316

    317

    318

    319

    320

    321

    322

    323

    324

    325

    326

    327

    328

    329

    330

    331

    332

    333

    334

    //------------------------------------------------------------------------------

    // <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.  

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

    1

    2

    3

    4

    5

    6

    7

    8

    9

    public Timer()

    : base() {

        interval = 100;

        enabled = false;

        autoReset = true;

        initializing = false;

        delayedEnable = false;

        callback = new TimerCallback(this.MyTimerCallback);

    }

    而如果你是这样的话

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    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的代码实现是这样的.

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    /// <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;

        }

    }

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

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    17

    18

    19

    20

    21

    22

    23

    24

    25

    26

    27

    28

    29

    30

    31

    32

    33

    34

    35

    36

    37

    38

    39

    40

    41

    42

    43

    44

    45

    46

    47

    48

    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/

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

  • 相关阅读:
    MSSQL 2012 密钥
    同台同时多开DELPHI2007的解决办法
    DELPHI快捷键
    Delphi编码规范
    解决Delphi 2010启动时卡死并报“displayNotification: 堆栈溢出”错误
    Test
    sched python 定时任务
    springboot2.x 整合redis
    springboot 忽略null属性值,不传递
    logback.xml 配置使用
  • 原文地址:https://www.cnblogs.com/grj001/p/12223179.html
Copyright © 2020-2023  润新知