using System; using System.Threading; namespace Swan.Threading { /// /// Provides a Manual Reset Event factory with a unified API. /// /// /// The following example shows how to use the WaitEventFactory class. /// /// using Swan.Threading; /// /// public class Example /// { /// // create a WaitEvent using the slim version /// private static readonly IWaitEvent waitEvent = WaitEventFactory.CreateSlim(false); /// /// public static void Main() /// { /// Task.Factory.StartNew(() => /// { /// DoWork(1); /// }); /// /// Task.Factory.StartNew(() => /// { /// DoWork(2); /// }); /// /// // send first signal /// waitEvent.Complete(); /// waitEvent.Begin(); /// /// Thread.Sleep(TimeSpan.FromSeconds(2)); /// /// // send second signal /// waitEvent.Complete(); /// /// Terminal.Readline(); /// } /// /// public static void DoWork(int taskNumber) /// { /// $"Data retrieved:{taskNumber}".WriteLine(); /// waitEvent.Wait(); /// /// Thread.Sleep(TimeSpan.FromSeconds(2)); /// $"All finished up {taskNumber}".WriteLine(); /// } /// } /// /// public static class WaitEventFactory { #region Factory Methods /// /// Creates a Wait Event backed by a standard ManualResetEvent. /// /// if initially set to completed. Generally true. /// The Wait Event. public static IWaitEvent Create(Boolean isCompleted) => new WaitEvent(isCompleted); /// /// Creates a Wait Event backed by a ManualResetEventSlim. /// /// if initially set to completed. Generally true. /// The Wait Event. public static IWaitEvent CreateSlim(Boolean isCompleted) => new WaitEventSlim(isCompleted); /// /// Creates a Wait Event backed by a ManualResetEventSlim. /// /// if initially set to completed. Generally true. /// if set to true creates a slim version of the wait event. /// The Wait Event. public static IWaitEvent Create(Boolean isCompleted, Boolean useSlim) => useSlim ? CreateSlim(isCompleted) : Create(isCompleted); #endregion #region Backing Classes /// /// Defines a WaitEvent backed by a ManualResetEvent. /// private class WaitEvent : IWaitEvent { private ManualResetEvent _event; /// /// Initializes a new instance of the class. /// /// if set to true [is completed]. public WaitEvent(Boolean isCompleted) => this._event = new ManualResetEvent(isCompleted); /// public Boolean IsDisposed { get; private set; } /// public Boolean IsValid => this.IsDisposed || this._event == null ? false : this._event?.SafeWaitHandle?.IsClosed ?? true ? false : !(this._event?.SafeWaitHandle?.IsInvalid ?? true); /// public Boolean IsCompleted => this.IsValid == false ? true : this._event?.WaitOne(0) ?? true; /// public Boolean IsInProgress => !this.IsCompleted; /// public void Begin() => this._event?.Reset(); /// public void Complete() => this._event?.Set(); /// void IDisposable.Dispose() { if(this.IsDisposed) { return; } this.IsDisposed = true; _ = this._event?.Set(); this._event?.Dispose(); this._event = null; } /// public void Wait() => this._event?.WaitOne(); /// public Boolean Wait(TimeSpan timeout) => this._event?.WaitOne(timeout) ?? true; } /// /// Defines a WaitEvent backed by a ManualResetEventSlim. /// private class WaitEventSlim : IWaitEvent { private ManualResetEventSlim _event; /// /// Initializes a new instance of the class. /// /// if set to true [is completed]. public WaitEventSlim(Boolean isCompleted) => this._event = new ManualResetEventSlim(isCompleted); /// public Boolean IsDisposed { get; private set; } /// public Boolean IsValid => this.IsDisposed || this._event?.WaitHandle?.SafeWaitHandle == null ? false : !this._event.WaitHandle.SafeWaitHandle.IsClosed && !this._event.WaitHandle.SafeWaitHandle.IsInvalid; /// public Boolean IsCompleted => this.IsValid == false || this._event.IsSet; /// public Boolean IsInProgress => !this.IsCompleted; /// public void Begin() => this._event?.Reset(); /// public void Complete() => this._event?.Set(); /// void IDisposable.Dispose() { if(this.IsDisposed) { return; } this.IsDisposed = true; this._event?.Set(); this._event?.Dispose(); this._event = null; } /// public void Wait() => this._event?.Wait(); /// public Boolean Wait(TimeSpan timeout) => this._event?.Wait(timeout) ?? true; } #endregion } }