public override bool TryComplete(Exception error) { UnboundedChannel <T> parent = _parent; bool completeTask; lock (parent.SyncObj) { parent.AssertInvariants(); // If we've already marked the channel as completed, bail. if (parent._doneWriting != null) { return(false); } // Mark that we're done writing. parent._doneWriting = error ?? ChannelUtilities.s_doneWritingSentinel; completeTask = parent._items.IsEmpty; } // If there are no items in the queue, complete the channel's task, // as no more data can possibly arrive at this point. We do this outside // of the lock in case we'll be running synchronous completions, and we // do it before completing blocked/waiting readers, so that when they // wake up they'll see the task as being completed. if (completeTask) { ChannelUtilities.Complete(parent._completion, error); } // At this point, _blockedReaders and _waitingReaders will not be mutated: // they're only mutated by readers while holding the lock, and only if _doneWriting is null. // freely manipulate _blockedReaders and _waitingReaders without any concurrency concerns. ChannelUtilities.FailOperations <AsyncOperation <T>, T>(parent._blockedReaders, ChannelUtilities.CreateInvalidCompletionException(error)); ChannelUtilities.WakeUpWaiters(ref parent._waitingReadersTail, result: false, error: error); // Successfully transitioned to completed. return(true); }