using System; /// <summary> /// Provides a way of testing for whether a certain amount of time has /// elapsed. /// </summary> /// <remarks> /// <p>This is intended for use in loops which need to do some work until /// a specific amount of time has elapsed. For example, it can be used /// to test if a timeout has occurred yet. It can also be used in simple /// benchmark tests to see how many operations can be performed in a /// given amount of time.</p> /// /// <p>Its usage is:</p> /// <code> /// WaitForTicks wait = new WaitForTicks(TimeSpan.FromSeconds(2)); /// while (!wait.TimeIsUp) /// { /// ... do work ... /// } /// </code> /// /// <p>This uses the <see cref="Environment.TickCount"/>, which increases /// monotonically, so it will be unperturbed by changes to the system /// time. This class deals correctly with wrapping around, both when the /// tick count rolls from positive to negative, and when it rolls around /// through 0. However, because the tick count is a 32 bit number, this /// class cannot wait for more than <see cref="Int32.MaxValue"/> /// milliseconds.</p> /// </remarks> public class WaitForTicks { private readonly int startTicks; private readonly uint maxTicks; /// <summary> /// Create a WaitForTicks object initialized to expire in the /// specified amount of time. /// </summary> /// <param name="time">The amount of time into the future in /// which this timer's <see cref="TimeIsUp"/> property will /// return true.</param> /// <exception cref="ArgumentOutOfRangeException">Thrown if /// the specified time is more than <see cref="Int32.MaxValue"/> /// millseconds in the future.</exception> public WaitForTicks(TimeSpan time) { double fullMaxTicks = time.TotalMilliseconds; if (fullMaxTicks > int.MaxValue) { // The int.MaxValue limit is a bit arbitrary. In practice, // the limit will depend on how often code checks the // TimeIsUp property. Here, they have another // int.MaxValue seconds to check it. (They have to // check it before the difference rolls round.) // You could narrow the margin. For example, // testing for fullMaxTicks > uint.MaxValue - 10000 // would be OK if you were testing the value at least // once every 10 seconds. // With the code as it is, there's a safety margin of // some 24.5 days! throw new ArgumentOutOfRangeException("time", time, "Cannot wait for more than Int32.MaxValue milliseconds"); } maxTicks = (uint) fullMaxTicks; startTicks = Environment.TickCount; } /// <summary> /// Returns true if the amount of time specified at construction has /// elapsed since construction. /// </summary> public bool TimeIsUp { get { uint diff = (uint) (Environment.TickCount - startTicks); return diff >= maxTicks; } } }