public static async Task <bool> WaitOneAsync(this WaitHandle handle, int millisecondsTimeout, CancellationToken cancellationToken) { RegisteredWaitHandle? registeredHandle = null; CancellationTokenRegistration tokenRegistration = default; try { var tcs = new TaskCompletionSource <bool>(); registeredHandle = ThreadPool.RegisterWaitForSingleObject( handle, (state, timedOut) => ((TaskCompletionSource <bool>)state !).TrySetResult(!timedOut), tcs, millisecondsTimeout, true); tokenRegistration = cancellationToken.Register( state => ((TaskCompletionSource <bool>)state !).TrySetCanceled(), tcs); return(await tcs.Task); } finally { registeredHandle?.Unregister(null); tokenRegistration.Dispose(); } }
// http://stackoverflow.com/questions/25382583/waiting-on-a-named-semaphore-with-waitone100-vs-waitone0-task-delay100 // http://blog.nerdbank.net/2011/07/c-await-for-waithandle.html // F# has a AwaitWaitHandle method that accepts a time out... and seems pretty complex... // version below should be OK public static Task WaitOneAsync(this WaitHandle handle, int millisecondsTimeout = Timeout.Infinite) { var tcs = new TaskCompletionSource <object?>(); var callbackHandleInitLock = new object(); lock (callbackHandleInitLock) { RegisteredWaitHandle?callbackHandle = null; // ReSharper disable once RedundantAssignment callbackHandle = ThreadPool.RegisterWaitForSingleObject( handle, (state, timedOut) => { //TODO: We aren't checking if this is timed out tcs.SetResult(null); // we take a lock here to make sure the outer method has completed setting the local variable callbackHandle. lock (callbackHandleInitLock) { // ReSharper disable once PossibleNullReferenceException // ReSharper disable once AccessToModifiedClosure callbackHandle?.Unregister(null); } }, /*state:*/ null, /*millisecondsTimeOutInterval:*/ millisecondsTimeout, /*executeOnlyOnce:*/ true); } return(tcs.Task); }
/// <summary> /// Asynchronously waits for the process to exit. /// </summary> public static Task WaitForExitAsync(this Process process) { if (process.HasExited) { return(Task.CompletedTask); } var safeProcessHandle = process.SafeHandle; if (safeProcessHandle.IsClosed) { throw new ObjectDisposedException("Process"); } var tcs = new TaskCompletionSource <object?>(); var waitHandle = new ProcessWaitHandle(safeProcessHandle); RegisteredWaitHandle?registeredWaitHandle = null; lock (tcs) { registeredWaitHandle = ThreadPool.RegisterWaitForSingleObject(waitHandle, WaitForExitAsyncCallback, null, -1, true); } return(tcs.Task); void WaitForExitAsyncCallback(object context, bool wasSignaled) { // The lock is used to ensure `registeredWaitHandle` is initialized here // even if the process terminates while `RegisterWaitForSingleObject` is returning. lock (tcs) { registeredWaitHandle !.Unregister(null); } waitHandle.Close(); tcs.SetResult(null); } }
// Reference: ASYNC AND CANCELLATION SUPPORT FOR WAIT HANDLES // https://thomaslevesque.com/2015/06/04/async-and-cancellation-support-for-wait-handles/ internal static async Task <bool> WaitOneAsync(this WaitHandle handle, int millisecondsTimeout, CancellationToken cancellationToken) { if (handle == null) { throw new ArgumentNullException($"{nameof(handle)} is null"); } RegisteredWaitHandle? registeredHandle = null; CancellationTokenRegistration tokenRegistration = default; try { var tcs = new TaskCompletionSource <bool>(); registeredHandle = ThreadPool.RegisterWaitForSingleObject( handle, (state, timedOut) => ((TaskCompletionSource <bool>)state).TrySetResult(!timedOut), tcs, millisecondsTimeout, true); tokenRegistration = cancellationToken.Register( state => ((TaskCompletionSource <bool>)state).TrySetCanceled(), tcs); return(await tcs.Task.ConfigureAwait(false)); } finally { registeredHandle?.Unregister(null); tokenRegistration.Dispose(); } }
private async Task <T> InvokeAsync <T>( Delegate invokeDelegate, TimeSpan timeOutSpan = default, CancellationToken cancellationToken = default, params object[] args) { var tokenRegistration = default(CancellationTokenRegistration); RegisteredWaitHandle?registeredWaitHandle = null; try { TaskCompletionSource <bool> taskCompletionSource = new(); IAsyncResult?asyncResult = BeginInvoke(invokeDelegate, args); registeredWaitHandle = ThreadPool.RegisterWaitForSingleObject( asyncResult.AsyncWaitHandle, new WaitOrTimerCallback(InvokeAsyncCallBack), taskCompletionSource, timeOutSpan.Milliseconds, true); tokenRegistration = cancellationToken.Register( CancellationTokenRegistrationCallBack, taskCompletionSource); await taskCompletionSource.Task; object?returnObject = EndInvoke(asyncResult); return((T)returnObject); } finally { registeredWaitHandle?.Unregister(null); tokenRegistration.Dispose(); }
// based on http://www.thomaslevesque.com/2015/06/04/async-and-cancellation-support-for-wait-handles/ private static async Task <bool> WaitOneAsync(WaitHandle handle, int timeoutMillis, CancellationToken cancellationToken) { RegisteredWaitHandle? registeredHandle = null; CancellationTokenRegistration tokenRegistration = default; try { var taskCompletionSource = new TaskCompletionSource <bool>(); registeredHandle = ThreadPool.RegisterWaitForSingleObject( handle, (state, timedOut) => ((TaskCompletionSource <bool>)state).TrySetResult(!timedOut), state: taskCompletionSource, millisecondsTimeOutInterval: timeoutMillis, executeOnlyOnce: true ); tokenRegistration = cancellationToken.Register( state => ((TaskCompletionSource <bool>)state).TrySetCanceled(), state: taskCompletionSource ); return(await taskCompletionSource.Task.ConfigureAwait(false)); } finally { if (registeredHandle != null) { // this is different from the referenced site, but I think this is more correct: // the handle passed to unregister is a handle to be signaled, not the one to unregister // (that one is already captured by the registered handle). See // http://referencesource.microsoft.com/#mscorlib/system/threading/threadpool.cs,065408fc096354fd registeredHandle.Unregister(null); } tokenRegistration.Dispose(); } }
public static async Task <bool> WaitOneAsync(this WaitHandle handle, int millisecondsTimeout, CancellationToken?cancellationToken) { RegisteredWaitHandle? registeredHandle = null; CancellationTokenRegistration?tokenRegistration = null; try { var tcs = new TaskCompletionSource <bool>(); registeredHandle = ThreadPool.RegisterWaitForSingleObject( handle, (state, timedOut) => ((TaskCompletionSource <bool>)state).TrySetResult(!timedOut), tcs, millisecondsTimeout, true); if (cancellationToken.HasValue) { tokenRegistration = cancellationToken.Value.Register( state => ((TaskCompletionSource <bool>)state).TrySetCanceled(), tcs); } return(await tcs.Task.ConfigureAwait(false)); } finally { if (registeredHandle != null) { registeredHandle.Unregister(null); } tokenRegistration?.Dispose(); } }
/// <devdoc> /// Make sure we are not watching for process exit. /// </devdoc> /// <internalonly/> private void StopWatchingForExit() { if (_watchingForExit) { RegisteredWaitHandle?rwh = null; WaitHandle? wh = null; lock (this) { if (_watchingForExit) { _watchingForExit = false; wh = _waitHandle; _waitHandle = null; rwh = _registeredWaitHandle; _registeredWaitHandle = null; } } if (rwh != null) { rwh.Unregister(null); } if (wh != null) { wh.Dispose(); } } }
//**************************************** internal void Register() { // Ensure the callback is only registered once if (_HandleState != Status.Unregistered || Interlocked.CompareExchange(ref _HandleState, Status.Registered, Status.Unregistered) != Status.Unregistered) { return; } _Registration = ThreadPool.RegisterWaitForSingleObject(WaitObject, OnWaitForSingleObject, this, Timeout.Infinite, false); }
public void Dispose() { if (_disposed) { return; } _disposed = true; _registeredWaitHandle?.Unregister(null); _handle?.Dispose(); _registeredWaitHandle = null; _handle = null; }
/// <summary> /// Creates a TPL Task that is marked as completed when a <see cref="WaitHandle"/> is signaled. /// </summary> /// <param name="handle">The handle whose signal triggers the task to be completed.</param> /// <param name="timeout">The amount of time to wait before timing out.</param> /// <param name="cancellationToken">The cancellation token.</param> /// <returns> /// A <see cref="Task{T}"/> that is completed after the handle is signaled. The result will be /// <see langword="true"/> if the <see cref="WaitHandle"/> was triggered before <paramref name="timeout"/> /// elapses, <see langword="false"/> otherwise. /// </returns> /// <remarks> /// https://thomaslevesque.com/2015/06/04/async-and-cancellation-support-for-wait-handles/ /// https://github.com/StephenCleary/AsyncEx/blob/master/src/Nito.AsyncEx.Interop.WaitHandles/Interop/WaitHandleAsyncFactory.cs /// </remarks> public static async Task <bool> ToTask(this WaitHandle handle, TimeSpan timeout, CancellationToken cancellationToken) { Guard.IsNotNull(handle, nameof(handle)); // Handle synchronous cases. bool alreadySignaled = handle.WaitOne(0); if (alreadySignaled) { return(true); } if (timeout == TimeSpan.Zero) { return(false); } cancellationToken.ThrowIfCancellationRequested(); RegisteredWaitHandle? registeredHandle = null; CancellationTokenRegistration tokenRegistration = default; try { var tcs = new TaskCompletionSource <bool>(TaskCreationOptions.RunContinuationsAsynchronously); registeredHandle = ThreadPool.RegisterWaitForSingleObject( handle, (state, timedOut) => ((TaskCompletionSource <bool>)state !).TrySetResult(!timedOut), tcs, timeout, true); tokenRegistration = cancellationToken.Register(state => ((TaskCompletionSource <bool>)state !).TrySetCanceled(), tcs); return(await tcs.Task.ConfigureAwait(false)); } finally { registeredHandle?.Unregister(null); tokenRegistration.Dispose(); } }
/// <summary> /// Asynchronously waits for the wait handle. /// </summary> /// <param name="handle">The handle.</param> /// <param name="timeout">The timeout.</param> /// <param name="cancellationToken">The cancellation token.</param> /// <returns><c>true</c> if the timeout has not been reached, <c>false</c> otherwise.</returns> public static async ValueTask <bool> WaitOneAsync( this WaitHandle handle, TimeSpan timeout, CancellationToken cancellationToken) { RegisteredWaitHandle? registeredHandle = null; CancellationTokenRegistration tokenRegistration = default; try { var tcs = new TaskCompletionSource <bool>(); registeredHandle = ThreadPool.RegisterWaitForSingleObject( handle, ( state, timedOut) => ((TaskCompletionSource <bool>)state !).TrySetResult(!timedOut), tcs, timeout, true); tokenRegistration = cancellationToken.Register( state => state.TrySetCanceled(), tcs); return(await tcs.Task); } finally { registeredHandle?.Unregister(null); #if NETSTANDARD21_OR_GREATER await tokenRegistration.DisposeAsync(); #else tokenRegistration.Dispose(); #endif } }
/// <summary> /// Ensures that the current process is being watched for exit events. /// </summary> public void Start() { if (!_watchingForExit) { lock (this) { if (!_watchingForExit) { _watchingForExit = true; try { _waitHandle = new ProcessWaitHandle(_handle); _registeredWaitHandle = ThreadPool.RegisterWaitForSingleObject(_waitHandle, CompletionCallback, null, -1, true); } catch { _watchingForExit = false; throw; } } } } }
/// <summary> /// 开始检查线程池 /// </summary> public static void CheckThreadPool() { //检查线程是否结束 _rhw = ThreadPool.RegisterWaitForSingleObject(new AutoResetEvent(false), CheckThreadPool, null, 1000, false); }
public WaitHandleBarrier(string name) { Name = name; _handle = new ManualResetEvent(false); _registeredWaitHandle = ThreadPool.RegisterWaitForSingleObject(_handle, OnRun, null, BarrierManager.WaitHandleTimeout, true); }
/// <summary> /// The main routine for the wait thread. /// </summary> private void WaitThreadStart() { while (true) { ProcessRemovals(); int numUserWaits = _numUserWaits; int preWaitTimeMs = Environment.TickCount; // Recalculate Timeout int timeoutDurationMs = Timeout.Infinite; if (numUserWaits == 0) { timeoutDurationMs = ThreadPoolThreadTimeoutMs; } else { for (int i = 0; i < numUserWaits; i++) { if (_registeredWaits[i].IsInfiniteTimeout) { continue; } int handleTimeoutDurationMs = _registeredWaits[i].TimeoutTimeMs - preWaitTimeMs; if (timeoutDurationMs == Timeout.Infinite) { timeoutDurationMs = handleTimeoutDurationMs > 0 ? handleTimeoutDurationMs : 0; } else { timeoutDurationMs = Math.Min(handleTimeoutDurationMs > 0 ? handleTimeoutDurationMs : 0, timeoutDurationMs); } if (timeoutDurationMs == 0) { break; } } } int signaledHandleIndex = WaitHandle.WaitAny(new ReadOnlySpan <WaitHandle>(_waitHandles, 0, numUserWaits + 1), timeoutDurationMs); if (signaledHandleIndex == 0) // If we were woken up for a change in our handles, continue. { continue; } RegisteredWaitHandle?signaledHandle = signaledHandleIndex != WaitHandle.WaitTimeout ? _registeredWaits[signaledHandleIndex - 1] : null; if (signaledHandle != null) { QueueWaitCompletion(signaledHandle, false); } else { if (numUserWaits == 0) { if (ThreadPoolInstance.TryRemoveWaitThread(this)) { return; } } int elapsedDurationMs = Environment.TickCount - preWaitTimeMs; // Calculate using relative time to ensure we don't have issues with overflow wraparound for (int i = 0; i < numUserWaits; i++) { RegisteredWaitHandle registeredHandle = _registeredWaits[i]; int handleTimeoutDurationMs = registeredHandle.TimeoutTimeMs - preWaitTimeMs; if (elapsedDurationMs >= handleTimeoutDurationMs) { QueueWaitCompletion(registeredHandle, true); } } } } }