namespace Unosquare.Swan.Components { using System; using System.Diagnostics; using System.Threading; using System.Threading.Tasks; using Abstractions; /// /// Represents logic providing several delay mechanisms. /// /// /// The following example shows how to implement delay mechanisms. /// /// using Unosquare.Swan.Components; /// /// 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 bool _isDisposed; private IWaitEvent _delayEvent; /// /// Initializes a new instance of the class. /// /// The strategy. public DelayProvider(DelayStrategy strategy = DelayStrategy.TaskDelay) { 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 (_syncRoot) { if (_isDisposed) return TimeSpan.Zero; _delayStopwatch.Restart(); switch (Strategy) { case DelayStrategy.ThreadSleep: DelaySleep(); break; case DelayStrategy.TaskDelay: DelayTask(); break; #if !NETSTANDARD1_3 case DelayStrategy.ThreadPool: DelayThreadPool(); break; #endif } return _delayStopwatch.Elapsed; } } #region Dispose Pattern /// public void Dispose() { lock (_syncRoot) { if (_isDisposed) return; _isDisposed = true; _delayEvent?.Dispose(); } } #endregion #region Private Delay Mechanisms private static void DelaySleep() => Thread.Sleep(15); private static void DelayTask() => Task.Delay(1).Wait(); #if !NETSTANDARD1_3 private void DelayThreadPool() { if (_delayEvent == null) _delayEvent = WaitEventFactory.Create(isCompleted: true, useSlim: true); _delayEvent.Begin(); ThreadPool.QueueUserWorkItem((s) => { DelaySleep(); _delayEvent.Complete(); }); _delayEvent.Wait(); } #endif #endregion } }