Example #1
0
 /// <summary>Mark the channel as being complete, meaning no more items will be written to it.</summary>
 /// <param name="error">Optional Exception indicating a failure that's causing the channel to complete.</param>
 /// <exception cref="InvalidOperationException">The channel has already been marked as complete.</exception>
 public void Complete(Exception error = null)
 {
     if (!TryComplete(error))
     {
         throw ChannelUtilities.CreateInvalidCompletionException();
     }
 }
Example #2
0
        /// <summary>Asynchronously writes an item to the channel.</summary>
        /// <param name="item">The value to write to the channel.</param>
        /// <param name="cancellationToken">A <see cref="CancellationToken"/> used to cancel the write operation.</param>
        /// <returns>A <see cref="Task"/> that represents the asynchronous write operation.</returns>
        public virtual Task WriteAsync(T item, CancellationToken cancellationToken = default(CancellationToken))
        {
            try
            {
                return
                    (cancellationToken.IsCancellationRequested ? Task.FromCanceled <T>(cancellationToken) :
                     TryWrite(item) ? Task.CompletedTask :
                     WriteAsyncCore(item, cancellationToken));
            }
            catch (Exception e)
            {
                return(Task.FromException(e));
            }

            async Task WriteAsyncCore(T innerItem, CancellationToken ct)
            {
                while (await WaitToWriteAsync(ct).ConfigureAwait(false))
                {
                    if (TryWrite(innerItem))
                    {
                        return;
                    }
                }

                throw ChannelUtilities.CreateInvalidCompletionException();
            }
        }
            public override Task <bool> WaitToReadAsync(CancellationToken cancellationToken)
            {
                // If there are any items, readers can try to get them.
                return(!_parent._items.IsEmpty ?
                       ChannelUtilities.s_trueTask :
                       WaitToReadAsyncCore(cancellationToken));

                Task <bool> WaitToReadAsyncCore(CancellationToken ct)
                {
                    UnboundedChannel <T> parent = _parent;

                    lock (parent.SyncObj)
                    {
                        parent.AssertInvariants();

                        // Try again to read now that we're synchronized with writers.
                        if (!parent._items.IsEmpty)
                        {
                            return(ChannelUtilities.s_trueTask);
                        }

                        // There are no items, so if we're done writing, there's never going to be data available.
                        if (parent._doneWriting != null)
                        {
                            return(parent._doneWriting != ChannelUtilities.s_doneWritingSentinel ?
                                   Task.FromException <bool>(parent._doneWriting) :
                                   ChannelUtilities.s_falseTask);
                        }

                        // Queue the waiter
                        return(ChannelUtilities.GetOrCreateWaiter(ref parent._waitingReaders, parent._runContinuationsAsynchronously, ct));
                    }
                }
            }
            public override Task <bool> WaitToReadAsync(CancellationToken cancellationToken)
            {
                if (cancellationToken.IsCancellationRequested)
                {
                    return(Task.FromCanceled <bool>(cancellationToken));
                }

                BoundedChannel <T> parent = _parent;

                lock (parent.SyncObj)
                {
                    parent.AssertInvariants();

                    // If there are any items available, a read is possible.
                    if (!parent._items.IsEmpty)
                    {
                        return(ChannelUtilities.s_trueTask);
                    }

                    // There were no items available, so if we're done writing, a read will never be possible.
                    if (parent._doneWriting != null)
                    {
                        return(parent._doneWriting != ChannelUtilities.s_doneWritingSentinel ?
                               Task.FromException <bool>(parent._doneWriting) :
                               ChannelUtilities.s_falseTask);
                    }

                    // There were no items available, but there could be in the future, so ensure
                    // there's a blocked reader task and return it.
                    return(ChannelUtilities.GetOrCreateWaiter(ref parent._waitingReaders, parent._runContinuationsAsynchronously, cancellationToken));
                }
            }
            public override bool TryRead(out T item)
            {
                SingleConsumerUnboundedChannel <T> parent = _parent;

                if (parent._items.TryDequeue(out item))
                {
                    if (parent._doneWriting != null && parent._items.IsEmpty)
                    {
                        ChannelUtilities.Complete(parent._completion, parent._doneWriting);
                    }
                    return(true);
                }
                return(false);
            }
            public override bool TryRead(out T item)
            {
                UnboundedChannel <T> parent = _parent;

                // Dequeue an item if we can
                if (parent._items.TryDequeue(out item))
                {
                    if (parent._doneWriting != null && parent._items.IsEmpty)
                    {
                        // If we've now emptied the items queue and we're not getting any more, complete.
                        ChannelUtilities.Complete(parent._completion, parent._doneWriting);
                    }
                    return(true);
                }

                item = default(T);
                return(false);
            }
            /// <summary>Dequeues an item, and then fixes up our state around writers and completion.</summary>
            /// <returns>The dequeued item.</returns>
            private T DequeueItemAndPostProcess()
            {
                BoundedChannel <T> parent = _parent;

                Debug.Assert(Monitor.IsEntered(parent.SyncObj));

                // Dequeue an item.
                T item = parent._items.DequeueHead();

                // If we're now empty and we're done writing, complete the channel.
                if (parent._doneWriting != null && parent._items.IsEmpty)
                {
                    ChannelUtilities.Complete(parent._completion, parent._doneWriting);
                }

                // If there are any writers blocked, there's now room for at least one
                // to be promoted to have its item moved into the items queue.  We need
                // to loop while trying to complete the writer in order to find one that
                // hasn't yet been canceled (canceled writers transition to canceled but
                // remain in the physical queue).
                while (!parent._blockedWriters.IsEmpty)
                {
                    WriterInteractor <T> w = parent._blockedWriters.DequeueHead();
                    if (w.Success(default(VoidResult)))
                    {
                        parent._items.EnqueueTail(w.Item);
                        return(item);
                    }
                }

                // There was no blocked writer, so see if there's a WaitToWriteAsync
                // we should wake up.
                ChannelUtilities.WakeUpWaiters(ref parent._waitingWriters, result: true);

                // Return the item
                return(item);
            }
Example #8
0
            public override Task <bool> WaitToReadAsync(CancellationToken cancellationToken)
            {
                UnbufferedChannel <T> parent = _parent;

                lock (parent.SyncObj)
                {
                    // If we're done writing, fail.
                    if (parent._completion.Task.IsCompleted)
                    {
                        return(parent._completion.Task.IsFaulted ?
                               Task.FromException <bool>(parent._completion.Task.Exception.InnerException) :
                               ChannelUtilities.s_falseTask);
                    }

                    // If there's a blocked writer, we can read.
                    if (!parent._blockedWriters.IsEmpty)
                    {
                        return(ChannelUtilities.s_trueTask);
                    }

                    // Otherwise, queue the waiter.
                    return(ChannelUtilities.GetOrCreateWaiter(ref parent._waitingReaders, true, cancellationToken));
                }
            }