timer.cs
来自「没的 没的 没的 没的 没的 没的 没的 没的 没的 没的 没的 没的 没的 没」· CS 代码 · 共 754 行 · 第 1/2 页
CS
754 行
/* * Timer.cs - Implementation of the "System.Threading.Timer" class. * * Copyright (C) 2003 Southern Storm Software, Pty Ltd. * * Author: Russell Stuart <russell-savannah@stuart.id.au> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */namespace System.Threading{ using System; using System.Collections; public sealed class Timer : MarshalByRefObject, IDisposable { // // Static data used by the background thread that implements the timers. // private static AlarmClock alarmClock; // Implements timeouts private static Queue disposeQueue; // Timers waiting to die private static long now; // The current time private static AutoResetEvent threadWakeup; // Event the thread sleeps on private static Thread timerThread; // Thread that fires timers // // Internal object data. // private AlarmClock.IAlarm alarm; // Thing that does the work private bool disposed; // True if Dispose() called private TimerCallback callback; // Thing to fire when timer expires private Object state; // State info to pass to Callback private WaitHandle notifyObject; // Who do notify when object disposed // // Private constructor - used to ensure all constructors initialise // the object in the same way. // private Timer(TimerCallback callback, Object state) { // // Validate the parameters. // if (callback == null) throw new ArgumentNullException("callback"); // // If this is the first timer constructed allocate resources // for the timer thread and start it. // lock (typeof(Timer)) { if (Timer.alarmClock == null) { if (!Thread.CanStartThreads()) throw new NotImplementedException(); Timer.alarmClock = new AlarmClock(); Timer.disposeQueue = new System.Collections.Queue(); Timer.now = Timer.UtcMilliseconds(); Timer.threadWakeup = new AutoResetEvent(false); Timer.timerThread = new Thread(new ThreadStart(Timer.Run)); Timer.timerThread.IsBackground = true; Timer.timerThread.Start(); } } // // Initialize the timer state. // this.disposed = false; this.alarm = Timer.alarmClock.CreateAlarm( new AlarmClock.AlarmExpiredHandler(this.fireTimer)); this.callback = callback; this.state = state; } // // Constructors. // public Timer(TimerCallback callback, Object state, int dueTime, int period) : this(callback, state) { this.Change(dueTime, period); } public Timer(TimerCallback callback, Object state, TimeSpan dueTime, TimeSpan period) : this(callback, state) { this.Change(dueTime, period); } #if !ECMA_COMPAT [CLSCompliant(false)] public Timer(TimerCallback callback, Object state, uint dueTime, uint period) : this(callback, state) { this.Change(dueTime, period); } public Timer(TimerCallback callback, Object state, long dueTime, long period) : this(callback, state) { this.Change(dueTime, period); } #endif // !ECMA_COMPAT // // Destructor. // ~Timer() { DisposeInternal(null); } // // Change the current timer parameters. // public bool Change(int dueTime, int period) { // // Validate the parameters. // if (dueTime < -1) { throw new ArgumentOutOfRangeException ("dueTime", _("ArgRange_NonNegOrNegOne")); } if (period < -1) { throw new ArgumentOutOfRangeException ("period", _("ArgRange_NonNegOrNegOne")); } // // Apparently trying to change the state of a disposed timer // is legal. // lock (this) { if (this.disposed) return false; } // // Set the new state. // long due = dueTime == -1 ? AlarmClock.INFINITE : dueTime; long interval = period <= 0 ? AlarmClock.INFINITE : period; Timer.AdvanceTime(); this.alarm.SetAlarm(due, interval); // // Wake up the background thread so it sees the new state. // Timer.threadWakeup.Set(); return true; } public bool Change(TimeSpan dueTime, TimeSpan period) { return Change(dueTime.Milliseconds, period.Milliseconds); } #if !ECMA_COMPAT [CLSCompliant(false)] public bool Change(uint dueTime, uint period) { return Change(UIntToMS(dueTime), UIntToMS(period)); } public bool Change(long dueTime, long period) { return Change(LongToMS(dueTime), LongToMS(period)); } #endif // !ECMA_COMPAT // // Dispose of this object. // public void Dispose() { DisposeInternal(null); } // // Dispose of this object and signal a particular wait // handle once the timer has been disposed. // public bool Dispose(WaitHandle notifyObject) { if (notifyObject == null) throw new ArgumentNullException("notifyObject"); return DisposeInternal(notifyObject); } // // Internal version of "Dispose". // private bool DisposeInternal(WaitHandle notifyObject) { lock (this) { if (this.disposed) return false; this.disposed = true; } this.alarm.SetAlarm(AlarmClock.INFINITE, AlarmClock.INFINITE); if (notifyObject != null) { this.notifyObject = notifyObject; lock (typeof(Timer)) Timer.disposeQueue.Enqueue(this); Timer.threadWakeup.Set(); } GC.SuppressFinalize(this); return true; } // // Convert an unsigned integer value into a milliseconds value. // internal static int UIntToMS(uint value) { if (value > (uint)(Int32.MaxValue)) { throw new ArgumentOutOfRangeException ("value", _("ArgRange_NonNegOrNegOne")); } return unchecked((int)value); } // // Convert a long integer value into a milliseconds value. // internal static int LongToMS(long value) { if (value < (-1L) || value > (long)(Int32.MaxValue)) { throw new ArgumentOutOfRangeException ("value", _("ArgRange_NonNegOrNegOne")); } return unchecked((int)value); } // // Return the current UTC time in milliseconds. // private static long UtcMilliseconds() { return DateTime.UtcNow.Ticks / TimeSpan.TicksPerMillisecond; } // // Method that runs the timer thread. // private static void Run() { for (;;) { // // Free up any Timer's awaiting destruction. Once this // is done the Timer is guarenteed to never fire again. // for (;;) { Timer timer; lock (typeof(Timer)) { if (Timer.disposeQueue.Count == 0) { break; } timer = (Timer)Timer.disposeQueue.Dequeue(); } (timer.notifyObject as ISignal).Signal(); } // // Sleep until an alarm is due to go off. // long longMs = Timer.alarmClock.TimeTillAlarm; int ms = longMs > int.MaxValue ? int.MaxValue : (int)longMs; Timer.threadWakeup.WaitOne(ms, false); Timer.AdvanceTime(); } } // // Advance the time in the Alarm object so it is the same as the // real time. // private static void AdvanceTime() { long elapsed; lock (typeof(Timer)) { long was = Timer.now; Timer.now = Timer.UtcMilliseconds(); elapsed = Timer.now - was; } Timer.alarmClock.Sleep(elapsed); } // // Called by the Alarm object when a time expires. Fire the // real Timer's callback. // private void fireTimer() { TimerCallback callback; Object state; lock (this) { callback = this.callback; state = this.state; } callback(state); } /// <summary>A generalised timeout class</summary> /// <remarks> /// <para> /// Think of an <see cref="AlarmClock"/> as an implementation of a /// real alarm clock - ie something that keeps track of time. Use /// <see cref="AlarmClock.CreateAlarm"/> to create /// any number of alarms - ie things that call their /// <see cref="AlarmClock.AlarmHandler"/> event when the alarm clock's /// time reaches a certain value. This value is set with /// <see cref="AlarmClock.Alarm.SetAlarm"/> - you can choose to have /// the alarm to fire just once or periodically. /// </para> /// /// <para> /// The only thing this alarm clock lacks is a timer - ie something /// that advances the time. You must do that for it by calling /// <see cref="AlarmClock.Sleep"/>, which advances the time by the /// number of "time units" passed. Calling <c>Sleep</c> fires any /// alarms set in the elapsed period. A time unit is what you /// define it to be - a tick, a second, a day or whatever. You /// must to be careful to ensure you use the same definition when /// passing time intervals to <c>SetAlarm</c> and to <c>Sleep</c>. /// <see cref="AlarmClock.TimeTillAlarm"/> tells you how long until /// the next alarm will fire. /// </para> /// /// <para> /// Note: timers / alarms are all pretty much identical, except /// in how they advance time. Threads, message loops, busy waits /// are all possibilities. Because this class omits that piece of /// the puzzle it can be used as the basis for all the others. /// </para> /// /// <para> /// The time need to manipulate N alarms is O(log2(N)), so this /// should be efficient for huge numbers of alarms. /// </para> /// </remarks> internal class AlarmClock { /// <summary>Disable a alarm.</summary> public const long INFINITE = long.MaxValue; /// <summary>A priority queue of Alarms.</summary> /// <remarks> /// The sort algroithm used by the queue is guarenteed to be /// "stable", meaning that alarms due to go off at the same /// time will fire in the order they were added.
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?