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
}
}