RaspberryIO_26/Swan/Threading/DelayProvider.cs
2019-12-08 21:23:54 +01:00

136 lines
3.4 KiB
C#

using System;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
namespace Swan.Threading {
/// <summary>
/// Represents logic providing several delay mechanisms.
/// </summary>
/// <example>
/// The following example shows how to implement delay mechanisms.
/// <code>
/// 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();
/// }
/// }
/// }
/// </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;
case DelayStrategy.ThreadPool:
this.DelayThreadPool();
break;
}
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();
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
}
}