/// <summary> /// Converts a <see cref="System.Threading.WaitHandle"/> to an observable sequence /// </summary> /// <param name="waitHandle">the value to convert</param> /// <param name="executeOnlyOnce">true to observe multiple signals, false to complete the stream when signaled</param> /// <param name="timeout">optional timeout waiting for a single</param> /// <returns>A sequence that completes when <paramref name="executeOnlyOnce"/> is true, or never completes, and signals when false. Returns a TimeoutException when timeout is hit.</returns> public static IObservable<Unit> ToObservable(this WaitHandle waitHandle, bool executeOnlyOnce, TimeSpan? timeout = null) { return Observable.Create<Unit> (observer => { RegisteredWaitHandle registration = null; registration = ThreadPool.UnsafeRegisterWaitForSingleObject ( waitHandle, (state, timedOut) => { if ((timedOut || executeOnlyOnce) && null != registration) registration.Unregister (waitHandle); if (timedOut) observer.OnError (new TimeoutException ()); else { observer.OnNext (Unit.Default); if (executeOnlyOnce) observer.OnCompleted (); } }, null, timeout.AsThreadingTimeout (), executeOnlyOnce); return () => registration.Unregister (waitHandle); }); }
/// <summary> /// Converts a <see cref="WaitHandle"/> into a disposable <see cref="Task"/> /// </summary> /// <param name="waitHandle">the operating-system specfic object to watch</param> /// <param name="timeout">optional timeout</param> /// <param name="asyncCallback">optional callback to call when the waitHandle signals</param> /// <param name="state">optional state to pass to the callback</param> /// <returns>An encapulted task - call Dispose on the result to unregister from the waitHandle's signal and cancel the task</returns> /// <remarks>Calling dispose on the task before it completes will result in an exception</remarks> public static IDisposable<Task> ToTask(this WaitHandle waitHandle, TimeSpan? timeout = null, AsyncCallback asyncCallback = null, object state = null) { var tcs = null == state ? new TaskCompletionSource<object> () : new TaskCompletionSource<object> (state); var registeredWaitHandle = ThreadPool.UnsafeRegisterWaitForSingleObject ( waitHandle, (o, timedOut) => { if (timedOut) tcs.TrySetException (new TimeoutException ()); else tcs.TrySetResult (o); }, state, timeout.AsThreadingTimeout (), true); Action unregister = () => registeredWaitHandle.Unregister (waitHandle); Task task = tcs.Task.ContinueWith (_ => unregister ()); IAsyncResult asyncResult = task; task = null == asyncCallback ? tcs.Task : tcs.Task.ContinueWith (_ => asyncCallback (asyncResult)); return new DisposableValue<Task> (task, () => { unregister (); tcs.TrySetCanceled (); }); }