예제 #1
0
            public override bool TryWrite(T item)
            {
                AsyncOperation <T>?   blockedReader      = null;
                AsyncOperation <bool>?waitingReadersTail = null;

                BoundedChannel <T> parent = _parent;

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

                    // If we're done writing, nothing more to do.
                    if (parent._doneWriting != null)
                    {
                        return(false);
                    }

                    // Get the number of items in the channel currently.
                    int count = parent._items.Count;

                    if (count == 0)
                    {
                        // There are no items in the channel, which means we may have blocked/waiting readers.

                        // If there are any blocked readers, find one that's not canceled
                        // and store it to complete outside of the lock, in case it has
                        // continuations that'll run synchronously
                        while (!parent._blockedReaders.IsEmpty)
                        {
                            AsyncOperation <T> r = parent._blockedReaders.DequeueHead();
                            r.UnregisterCancellation(); // ensure that once we grab it, we own its completion
                            if (!r.IsCompleted)
                            {
                                blockedReader = r;
                                break;
                            }
                        }

                        if (blockedReader == null)
                        {
                            // If there wasn't a blocked reader, then store the item. If no one's waiting
                            // to be notified about a 0-to-1 transition, we're done.
                            parent._items.EnqueueTail(item);
                            waitingReadersTail = parent._waitingReadersTail;
                            if (waitingReadersTail == null)
                            {
                                return(true);
                            }
                            parent._waitingReadersTail = null;
                        }
                    }
                    else if (count < parent._bufferedCapacity)
                    {
                        // There's room in the channel.  Since we're not transitioning from 0-to-1 and
                        // since there's room, we can simply store the item and exit without having to
                        // worry about blocked/waiting readers.
                        parent._items.EnqueueTail(item);
                        return(true);
                    }
                    else if (parent._mode == BoundedChannelFullMode.Wait)
                    {
                        // The channel is full and we're in a wait mode.
                        // Simply exit and let the caller know we didn't write the data.
                        return(false);
                    }
                    else if (parent._mode == BoundedChannelFullMode.DropWrite)
                    {
                        // The channel is full.  Just ignore the item being added
                        // but say we added it.
                        return(true);
                    }
                    else
                    {
                        // The channel is full, and we're in a dropping mode.
                        // Drop either the oldest or the newest and write the new item.
                        if (parent._mode == BoundedChannelFullMode.DropNewest)
                        {
                            parent._items.DequeueTail();
                        }
                        else
                        {
                            parent._items.DequeueHead();
                        }
                        parent._items.EnqueueTail(item);
                        return(true);
                    }
                }

                // We either wrote the item already, or we're transferring it to the blocked reader we grabbed.
                if (blockedReader != null)
                {
                    Debug.Assert(waitingReadersTail == null, "Shouldn't have any waiters to wake up");

                    // Transfer the written item to the blocked reader.
                    bool success = blockedReader.TrySetResult(item);
                    Debug.Assert(success, "We should always be able to complete the reader.");
                }
                else
                {
                    // We stored an item bringing the count up from 0 to 1.  Alert
                    // any waiting readers that there may be something for them to consume.
                    // Since we're no longer holding the lock, it's possible we'll end up
                    // waking readers that have since come in.
                    ChannelUtilities.WakeUpWaiters(ref waitingReadersTail, result: true);
                }

                return(true);
            }
예제 #2
0
 internal BoundedChannelWriter(BoundedChannel <T> parent)
 {
     _parent          = parent;
     _writerSingleton = new VoidAsyncOperationWithData <T>(runContinuationsAsynchronously: true, pooled: true);
     _waiterSingleton = new AsyncOperation <bool>(runContinuationsAsynchronously: true, pooled: true);
 }