Exemplo n.º 1
0
        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();
            }
        }
Exemplo n.º 2
0
        // 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);
        }
Exemplo n.º 3
0
        /// <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);
            }
        }
Exemplo n.º 4
0
        // 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();
            }
        }
Exemplo n.º 5
0
        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();
            }
        }
Exemplo n.º 8
0
        /// <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);
            }
Exemplo n.º 10
0
        public void Dispose()
        {
            if (_disposed)
            {
                return;
            }

            _disposed = true;
            _registeredWaitHandle?.Unregister(null);
            _handle?.Dispose();

            _registeredWaitHandle = null;
            _handle = null;
        }
Exemplo n.º 11
0
        /// <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();
            }
        }
Exemplo n.º 12
0
    /// <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
        }
    }
Exemplo n.º 13
0
 /// <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);
 }
Exemplo n.º 15
0
 public WaitHandleBarrier(string name)
 {
     Name    = name;
     _handle = new ManualResetEvent(false);
     _registeredWaitHandle = ThreadPool.RegisterWaitForSingleObject(_handle, OnRun, null, BarrierManager.WaitHandleTimeout, true);
 }
Exemplo n.º 16
0
            /// <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);
                            }
                        }
                    }
                }
            }