139 lines
3.5 KiB
C#
139 lines
3.5 KiB
C#
using System;
|
|
using System.Diagnostics;
|
|
using System.Threading;
|
|
using System.Threading.Tasks;
|
|
using Unosquare.Swan.Abstractions;
|
|
|
|
namespace Unosquare.Swan.Components {
|
|
/// <summary>
|
|
/// Represents logic providing several delay mechanisms.
|
|
/// </summary>
|
|
/// <example>
|
|
/// The following example shows how to implement delay mechanisms.
|
|
/// <code>
|
|
/// 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();
|
|
/// }
|
|
/// }
|
|
/// }
|
|
/// </code>
|
|
/// </example>
|
|
public sealed class DelayProvider : IDisposable {
|
|
private readonly Object _syncRoot = new Object();
|
|
private readonly Stopwatch _delayStopwatch = new Stopwatch();
|
|
|
|
private Boolean _isDisposed;
|
|
private IWaitEvent _delayEvent;
|
|
|
|
/// <summary>
|
|
/// Initializes a new instance of the <see cref="DelayProvider"/> class.
|
|
/// </summary>
|
|
/// <param name="strategy">The strategy.</param>
|
|
public DelayProvider(DelayStrategy strategy = DelayStrategy.TaskDelay) => this.Strategy = strategy;
|
|
|
|
/// <summary>
|
|
/// Enumerates the different ways of providing delays.
|
|
/// </summary>
|
|
public enum DelayStrategy {
|
|
/// <summary>
|
|
/// Using the Thread.Sleep(15) mechanism.
|
|
/// </summary>
|
|
ThreadSleep,
|
|
|
|
/// <summary>
|
|
/// Using the Task.Delay(1).Wait mechanism.
|
|
/// </summary>
|
|
TaskDelay,
|
|
|
|
/// <summary>
|
|
/// Using a wait event that completes in a background ThreadPool thread.
|
|
/// </summary>
|
|
ThreadPool,
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the selected delay strategy.
|
|
/// </summary>
|
|
public DelayStrategy Strategy {
|
|
get;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates the smallest possible, synchronous delay based on the selected strategy.
|
|
/// </summary>
|
|
/// <returns>The elapsed time of the delay.</returns>
|
|
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;
|
|
#if !NETSTANDARD1_3
|
|
case DelayStrategy.ThreadPool:
|
|
this.DelayThreadPool();
|
|
break;
|
|
#endif
|
|
}
|
|
|
|
return this._delayStopwatch.Elapsed;
|
|
}
|
|
}
|
|
|
|
#region Dispose Pattern
|
|
|
|
/// <inheritdoc />
|
|
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();
|
|
|
|
#if !NETSTANDARD1_3
|
|
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();
|
|
}
|
|
#endif
|
|
#endregion
|
|
}
|
|
} |