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 + -
显示快捷键?