/// <summary>Wake up all of the waiters and null out the field.</summary>
        /// <param name="waiters">The waiters.</param>
        /// <param name="result">The value with which to complete each waiter.</param>
        internal static void WakeUpWaiters(ref ReaderInteractor <bool> waiters, bool result)
        {
            ReaderInteractor <bool> w = waiters;

            if (w != null)
            {
                w.Success(result);
                waiters = null;
            }
        }
        /// <summary>Wake up all of the waiters and null out the field.</summary>
        /// <param name="waiters">The waiters.</param>
        /// <param name="result">The success value with which to complete each waiter if <paramref name="error">error</paramref> is null.</param>
        /// <param name="error">The failure with which to cmplete each waiter, if non-null.</param>
        internal static void WakeUpWaiters(ref ReaderInteractor <bool> waiters, bool result, Exception error = null)
        {
            ReaderInteractor <bool> w = waiters;

            if (w != null)
            {
                if (error != null)
                {
                    w.Fail(error);
                }
                else
                {
                    w.Success(result);
                }
                waiters = null;
            }
        }
            public override Task <bool> WaitToReadAsync(CancellationToken cancellationToken)
            {
                // Outside of the lock, check if there are any items waiting to be read.  If there are, we're done.
                return(!_parent._items.IsEmpty ?
                       ChannelUtilities.s_trueTask :
                       WaitToReadAsyncCore(cancellationToken));

                Task <bool> WaitToReadAsyncCore(CancellationToken ct)
                {
                    // Now check for cancellation.
                    if (ct.IsCancellationRequested)
                    {
                        return(Task.FromCanceled <bool>(ct));
                    }

                    SingleConsumerUnboundedChannel <T> parent = _parent;
                    ReaderInteractor <bool>            oldWaiter = null, newWaiter;

                    lock (parent.SyncObj)
                    {
                        // Again while holding the lock, check to see if there are any items available.
                        if (!parent._items.IsEmpty)
                        {
                            return(ChannelUtilities.s_trueTask);
                        }

                        // There aren't any items; if we're done writing, there never will be more items.
                        if (parent._doneWriting != null)
                        {
                            return(parent._doneWriting != ChannelUtilities.s_doneWritingSentinel ?
                                   Task.FromException <bool>(parent._doneWriting) :
                                   ChannelUtilities.s_falseTask);
                        }

                        // Create the new waiter.  We're a bit more tolerant of a stray waiting reader
                        // than we are of a blocked reader, as with usage patterns it's easier to leave one
                        // behind, so we just cancel any that may have been waiting around.
                        oldWaiter             = parent._waitingReader;
                        parent._waitingReader = newWaiter = ReaderInteractor <bool> .Create(parent._runContinuationsAsynchronously, ct);
                    }

                    oldWaiter?.TrySetCanceled();
                    return(newWaiter.Task);
                }
            }
        /// <summary>Gets or creates a "waiter" (e.g. WaitForRead/WriteAsync) interactor.</summary>
        /// <param name="waiter">The field storing the waiter interactor.</param>
        /// <param name="runContinuationsAsynchronously">true to force continuations to run asynchronously; otherwise, false.</param>
        /// <param name="cancellationToken">The token to use to cancel the wait.</param>
        internal static Task <bool> GetOrCreateWaiter(ref ReaderInteractor <bool> waiter, bool runContinuationsAsynchronously, CancellationToken cancellationToken)
        {
            // Get the existing waiters interactor.
            ReaderInteractor <bool> w = waiter;

            // If there isn't one, create one.  This explicitly does not include the cancellation token,
            // as we reuse it for any number of waiters that overlap.
            if (w == null)
            {
                waiter = w = ReaderInteractor <bool> .Create(runContinuationsAsynchronously);
            }

            // If the cancellation token can't be canceled, then just return the waiter task.
            // If it can, we need to return a task that will complete when the waiter task does but that can also be canceled.
            // Easiest way to do that is with a cancelable continuation.
            return(cancellationToken.CanBeCanceled ?
                   w.Task.ContinueWith(t => t.Result, cancellationToken, TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default) :
                   w.Task);
        }