コード例 #1
0
        internal static void WakeUpWaiters(ref AsyncOperation <bool>?listTail, bool result, Exception?error = null)
        {
            AsyncOperation <bool>?tail = listTail;

            if (tail != null)
            {
                listTail = null;

                AsyncOperation <bool> head = tail.Next !;
                AsyncOperation <bool> c    = head;
                do
                {
                    AsyncOperation <bool> next = c.Next !;
                    c.Next = null;

                    bool completed = error != null?c.TrySetException(error) : c.TrySetResult(result);

                    Debug.Assert(completed || c.CancellationToken.CanBeCanceled);

                    c = next;
                }while (c != head);
            }
        }
コード例 #2
0
            public override bool TryComplete(Exception error)
            {
                AsyncOperation <T>    blockedReader = null;
                AsyncOperation <bool> waitingReader = null;
                bool completeTask = false;

                SingleConsumerUnboundedChannel <T> parent = _parent;

                lock (parent.SyncObj)
                {
                    // If we're already marked as complete, there's nothing more to do.
                    if (parent._doneWriting != null)
                    {
                        return(false);
                    }

                    // Mark as complete for writing.
                    parent._doneWriting = error ?? ChannelUtilities.s_doneWritingSentinel;

                    // If we have no more items remaining, then the channel needs to be marked as completed
                    // and readers need to be informed they'll never get another item.  All of that needs
                    // to happen outside of the lock to avoid invoking continuations under the lock.
                    if (parent._items.IsEmpty)
                    {
                        completeTask = true;

                        if (parent._blockedReader != null)
                        {
                            blockedReader         = parent._blockedReader;
                            parent._blockedReader = null;
                        }

                        if (parent._waitingReader != null)
                        {
                            waitingReader         = parent._waitingReader;
                            parent._waitingReader = null;
                        }
                    }
                }

                // Complete the channel task if necessary
                if (completeTask)
                {
                    ChannelUtilities.Complete(parent._completion, error);
                }

                Debug.Assert(blockedReader == null || waitingReader == null, "There should only ever be at most one reader.");

                // Complete a blocked reader if necessary
                if (blockedReader != null)
                {
                    error = ChannelUtilities.CreateInvalidCompletionException(error);
                    blockedReader.TrySetException(error);
                }

                // Complete a waiting reader if necessary.  (We really shouldn't have both a blockedReader
                // and a waitingReader, but it's more expensive to prevent it than to just tolerate it.)
                if (waitingReader != null)
                {
                    if (error != null)
                    {
                        waitingReader.TrySetException(error);
                    }
                    else
                    {
                        waitingReader.TrySetResult(item: false);
                    }
                }

                // Successfully completed the channel
                return(true);
            }