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(bool 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(bool 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(bool isCompleted, bool 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(bool isCompleted)
{
_event = new ManualResetEvent(isCompleted);
}
///
public bool IsDisposed { get; private set; }
///
public bool IsValid
{
get
{
if (IsDisposed || _event == null)
return false;
if (_event?.SafeWaitHandle?.IsClosed ?? true)
return false;
return !(_event?.SafeWaitHandle?.IsInvalid ?? true);
}
}
///
public bool IsCompleted
{
get
{
if (IsValid == false)
return true;
return _event?.WaitOne(0) ?? true;
}
}
///
public bool IsInProgress => !IsCompleted;
///
public void Begin() => _event?.Reset();
///
public void Complete() => _event?.Set();
///
void IDisposable.Dispose()
{
if (IsDisposed) return;
IsDisposed = true;
_event?.Set();
_event?.Dispose();
_event = null;
}
///
public void Wait() => _event?.WaitOne();
///
public bool Wait(TimeSpan timeout) => _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(bool isCompleted)
{
_event = new ManualResetEventSlim(isCompleted);
}
///
public bool IsDisposed { get; private set; }
///
public bool IsValid
{
get
{
if (IsDisposed || _event?.WaitHandle?.SafeWaitHandle == null) return false;
return !_event.WaitHandle.SafeWaitHandle.IsClosed && !_event.WaitHandle.SafeWaitHandle.IsInvalid;
}
}
///
public bool IsCompleted => IsValid == false || _event.IsSet;
///
public bool IsInProgress => !IsCompleted;
///
public void Begin() => _event?.Reset();
///
public void Complete() => _event?.Set();
///
void IDisposable.Dispose()
{
if (IsDisposed) return;
IsDisposed = true;
_event?.Set();
_event?.Dispose();
_event = null;
}
///
public void Wait() => _event?.Wait();
///
public bool Wait(TimeSpan timeout) => _event?.Wait(timeout) ?? true;
}
#endregion
}
}