using System; using System.Diagnostics; using System.Threading; using System.Threading.Tasks; namespace Swan.Threading { /// /// Represents logic providing several delay mechanisms. /// /// /// The following example shows how to implement delay mechanisms. /// /// using Swan.Threading; /// /// public class Example /// { /// public static void Main() /// { /// // using the ThreadSleep strategy /// using (var delay = new DelayProvider(DelayProvider.DelayStrategy.ThreadSleep)) /// { /// // retrieve how much time was delayed /// var time = delay.WaitOne(); /// } /// } /// } /// /// public sealed class DelayProvider : IDisposable { private readonly Object _syncRoot = new Object(); private readonly Stopwatch _delayStopwatch = new Stopwatch(); private Boolean _isDisposed; private IWaitEvent _delayEvent; /// /// Initializes a new instance of the class. /// /// The strategy. public DelayProvider(DelayStrategy strategy = DelayStrategy.TaskDelay) => this.Strategy = strategy; /// /// Enumerates the different ways of providing delays. /// public enum DelayStrategy { /// /// Using the Thread.Sleep(15) mechanism. /// ThreadSleep, /// /// Using the Task.Delay(1).Wait mechanism. /// TaskDelay, /// /// Using a wait event that completes in a background ThreadPool thread. /// ThreadPool, } /// /// Gets the selected delay strategy. /// public DelayStrategy Strategy { get; } /// /// Creates the smallest possible, synchronous delay based on the selected strategy. /// /// The elapsed time of the delay. public TimeSpan WaitOne() { lock(this._syncRoot) { if(this._isDisposed) { return TimeSpan.Zero; } this._delayStopwatch.Restart(); switch(this.Strategy) { case DelayStrategy.ThreadSleep: DelaySleep(); break; case DelayStrategy.TaskDelay: DelayTask(); break; case DelayStrategy.ThreadPool: this.DelayThreadPool(); break; } return this._delayStopwatch.Elapsed; } } #region Dispose Pattern /// public void Dispose() { lock(this._syncRoot) { if(this._isDisposed) { return; } this._isDisposed = true; this._delayEvent?.Dispose(); } } #endregion #region Private Delay Mechanisms private static void DelaySleep() => Thread.Sleep(15); private static void DelayTask() => Task.Delay(1).Wait(); private void DelayThreadPool() { if(this._delayEvent == null) { this._delayEvent = WaitEventFactory.Create(isCompleted: true, useSlim: true); } this._delayEvent.Begin(); _ = ThreadPool.QueueUserWorkItem(s => { DelaySleep(); this._delayEvent.Complete(); }); this._delayEvent.Wait(); } #endregion } }