Ejemplo n.º 1
0
        /// <summary>Performs the asynchronous wait.</summary>
        /// <param name="asyncWaiter"></param>
        /// <param name="millisecondsTimeout">The timeout.</param>
        /// <param name="cancellationToken">The cancellation token.</param>
        /// <returns>The task to return to the caller.</returns>
        private async Task <bool> WaitUntilCountOrTimeoutAsync(TaskNode asyncWaiter, int millisecondsTimeout, CancellationToken cancellationToken)
        {
            Debug.Assert(asyncWaiter != null, "Waiter should have been constructed");
            //Debug.Assert(m_lock.IsAcquired, "Requires the lock be held");

            // Wait until either the task is completed, timeout occurs, or cancellation is requested.
            // We need to ensure that the Task.Delay task is appropriately cleaned up if the await
            // completes due to the asyncWaiter completing, so we use our own token that we can explicitly
            // cancel, and we chain the caller's supplied token into it.
            using (var cts = cancellationToken.CanBeCanceled ?
                             CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, default(CancellationToken)) :
                             new CancellationTokenSource())
            {
                var waitCompleted = Task.WhenAny(asyncWaiter, Task.Delay(millisecondsTimeout, cts.Token));
                if (asyncWaiter == await waitCompleted.ConfigureAwait(false))
                {
                    cts.Cancel(); // ensure that the Task.Delay task is cleaned up
                    return(true); // successfully acquired
                }
            }

            // If we get here, the wait has timed out or been canceled.

            // If the await completed synchronously, we still hold the lock.  If it didn't,
            // we no longer hold the lock.  As such, acquire it.
            //using (LockHolder.Hold(m_lock))
            lock (m_lockObject)
            {
                // Remove the task from the list.  If we're successful in doing so,
                // we know that no one else has tried to complete this waiter yet,
                // so we can safely cancel or timeout.
                if (RemoveAsyncWaiter(asyncWaiter))
                {
                    cancellationToken.ThrowIfCancellationRequested(); // cancellation occurred
                    return(false);                                    // timeout occurred
                }
            }

            // The waiter had already been removed, which means it's already completed or is about to
            // complete, so let it, and don't return until it does.
            return(await asyncWaiter.ConfigureAwait(false));
        }
Ejemplo n.º 2
0
        /// <summary>Performs the asynchronous wait.</summary>
        /// <param name="asyncWaiter">The asynchronous waiter.</param>
        /// <param name="millisecondsTimeout">The timeout.</param>
        /// <param name="cancellationToken">The cancellation token.</param>
        /// <returns>The task to return to the caller.</returns>
        private async Task <bool> WaitUntilCountOrTimeoutAsync(TaskNode asyncWaiter, int millisecondsTimeout, CancellationToken cancellationToken)
        {
            Debug.Assert(asyncWaiter != null, "Waiter should have been constructed");
            Debug.Assert(Monitor.IsEntered(m_lockObjAndDisposed), "Requires the lock be held");

            await new ConfiguredNoThrowAwaiter <bool>(asyncWaiter.WaitAsync(TimeSpan.FromMilliseconds(millisecondsTimeout), cancellationToken));

            if (cancellationToken.IsCancellationRequested)
            {
                // If we might be running as part of a cancellation callback, force the completion to be asynchronous
                // so as to maintain semantics similar to when no token is passed (neither Release nor Cancel would invoke
                // continuations off of this task).
                await TaskScheduler.Default;
            }

            if (asyncWaiter.IsCompleted)
            {
                return(true); // successfully acquired
            }

            // The wait has timed out or been canceled.

            // If the await completed synchronously, we still hold the lock.  If it didn't,
            // we no longer hold the lock.  As such, acquire it.
            lock (m_lockObjAndDisposed)
            {
                // Remove the task from the list.  If we're successful in doing so,
                // we know that no one else has tried to complete this waiter yet,
                // so we can safely cancel or timeout.
                if (RemoveAsyncWaiter(asyncWaiter))
                {
                    cancellationToken.ThrowIfCancellationRequested(); // cancellation occurred
                    return(false);                                    // timeout occurred
                }
            }

            // The waiter had already been removed, which means it's already completed or is about to
            // complete, so let it, and don't return until it does.
            return(await asyncWaiter.ConfigureAwait(false));
        }