/// <summary>Dequeues an item, and then fixes up our state around writers and completion.</summary> /// <returns>The dequeued item.</returns> private T DequeueItemAndPostProcess() { Debug.Assert(Monitor.IsEntered(SyncObj)); // Dequeue an item. T item = _items.DequeueHead(); // If we're now empty and we're done writing, complete the channel. if (_doneWriting != null && _items.IsEmpty) { ChannelUtilities.Complete(_completion, _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 (!_blockedWriters.IsEmpty) { WriterInteractor <T> w = _blockedWriters.DequeueHead(); if (w.Success(default(VoidResult))) { _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 _waitingWriters, result: true); // Return the item return(item); }
private ValueTask <T> ReadAsyncCore(CancellationToken cancellationToken) { if (cancellationToken.IsCancellationRequested) { return(new ValueTask <T>(Task.FromCanceled <T>(cancellationToken))); } lock (SyncObj) { AssertInvariants(); // If we're already completed, nothing to read. if (_completion.Task.IsCompleted) { return(new ValueTask <T>( _completion.Task.IsCanceled ? Task.FromCanceled <T>(new CancellationToken(true)) : Task.FromException <T>( _completion.Task.IsFaulted ? ChannelUtilities.CreateInvalidCompletionException(_completion.Task.Exception.InnerException) : ChannelUtilities.CreateInvalidCompletionException()))); } // If there are any blocked writers, find one to pair up with // and get its data. Writers that got canceled will remain in the queue, // so we need to loop to skip past them. while (!_blockedWriters.IsEmpty) { WriterInteractor <T> w = _blockedWriters.DequeueHead(); if (w.Success(default(VoidResult))) { return(new ValueTask <T>(w.Item)); } } // No writer found to pair with. Queue the reader. var r = ReaderInteractor <T> .Create(true, cancellationToken); _blockedReaders.EnqueueTail(r); // And let any waiting writers know it's their lucky day. ChannelUtilities.WakeUpWaiters(ref _waitingWriters, result: true); return(new ValueTask <T>(r.Task)); } }
private bool TryRead(out T item) { lock (SyncObj) { AssertInvariants(); // Try to find a writer to pair with while (!_blockedWriters.IsEmpty) { WriterInteractor <T> w = _blockedWriters.DequeueHead(); if (w.Success(default(VoidResult))) { item = w.Item; return(true); } } } // None found item = default(T); return(false); }