コード例 #1
0
        /// <summary>
        /// Attempts to enqueue an item.
        /// </summary>
        /// <param name="item">The item to enqueue.</param>
        /// <param name="cancellationToken">A cancellation token that can be used to abort the enqueue operation. If <paramref name="abort"/> is not <c>null</c>, then this token must include signals from the <paramref name="abort"/> object.</param>
        /// <param name="abort">A synchronization object used to cancel related enqueue operations. May be <c>null</c> if this is the only enqueue operation.</param>
        internal async Task <AsyncProducerConsumerQueue <T> > TryEnqueueAsync(T item, CancellationToken cancellationToken, TaskCompletionSource abort)
        {
            try
            {
                using (var combinedToken = CancellationTokenHelpers.Normalize(_completed.Token, cancellationToken))
                    using (await _mutex.LockAsync().ConfigureAwait(false))
                    {
                        // Wait for the queue to be not full.
                        while (Full)
                        {
                            await _notFull.WaitAsync(combinedToken.Token).ConfigureAwait(false);
                        }

                        // Explicitly check whether the queue has been marked complete to prevent a race condition where notFull is signalled at the same time the queue is marked complete.
                        if (_completed.IsCancellationRequested)
                        {
                            return(null);
                        }

                        // Set the abort signal. If another queue has already set the abort signal, then abort.
                        if (abort != null && !abort.TrySetCanceled())
                        {
                            return(null);
                        }

                        _queue.Enqueue(item);
                        _completedOrNotEmpty.Notify();
                        return(this);
                    }
            }
            catch (OperationCanceledException)
            {
                return(null);
            }
        }
コード例 #2
0
        /// <summary>
        /// Attempts to enqueue an item. This method may block the calling thread.
        /// </summary>
        /// <param name="item">The item to enqueue.</param>
        /// <param name="cancellationToken">A cancellation token that can be used to abort the enqueue operation.</param>
        internal AsyncProducerConsumerQueue <T> DoTryEnqueue(T item, CancellationToken cancellationToken)
        {
            try
            {
                using (var combinedToken = CancellationTokenHelpers.Normalize(_completed.Token, cancellationToken))
                    using (_mutex.Lock())
                    {
                        // Wait for the queue to be not full.
                        while (Full)
                        {
                            _notFull.Wait(combinedToken.Token);
                        }

                        // Explicitly check whether the queue has been marked complete to prevent a race condition where notFull is signalled at the same time the queue is marked complete.
                        if (_completed.IsCancellationRequested)
                        {
                            return(null);
                        }

                        _queue.Enqueue(item);
                        _completedOrNotEmpty.Notify();
                        return(this);
                    }
            }
            catch (OperationCanceledException)
            {
                return(null);
            }
        }
コード例 #3
0
        /// <summary>
        /// Attempts to enqueue an item to any of a number of producer/consumer queues. Returns the producer/consumer queue that received the item. Returns <c>null</c> if all producer/consumer queues have completed adding.
        /// </summary>
        /// <param name="queues">The producer/consumer queues.</param>
        /// <param name="item">The item to enqueue.</param>
        /// <param name="cancellationToken">A cancellation token that can be used to abort the enqueue operation.</param>
        /// <returns>The producer/consumer queue that received the item.</returns>
        public static async Task <AsyncProducerConsumerQueue <T> > TryEnqueueToAnyAsync <T>(this IEnumerable <AsyncProducerConsumerQueue <T> > queues, T item, CancellationToken cancellationToken)
        {
            var abort = new TaskCompletionSource();

            using (var abortCancellationToken = CancellationTokenHelpers.FromTask(abort.Task))
                using (var combinedToken = CancellationTokenHelpers.Normalize(abortCancellationToken.Token, cancellationToken))
                {
                    var token   = combinedToken.Token;
                    var tasks   = queues.Select(q => q.TryEnqueueAsync(item, token, abort));
                    var results = await TaskShim.WhenAll(tasks).ConfigureAwait(false);

                    var ret = results.FirstOrDefault(x => x != null);
                    if (ret == null)
                    {
                        cancellationToken.ThrowIfCancellationRequested();
                    }
                    return(ret);
                }
        }
コード例 #4
0
        /// <summary>
        /// Attempts to take an item from any of a number of producer/consumer collections. The operation "fails" if all the producer/consumer collections have completed adding and are empty, or if any take operation on an underlying collection fails.
        /// </summary>
        /// <param name="collections">The producer/consumer collections.</param>
        /// <param name="cancellationToken">A cancellation token that can be used to abort the take operation.</param>
        public static async Task <AsyncCollection <T> .TakeResult> TryTakeFromAnyAsync <T>(this IEnumerable <AsyncCollection <T> > collections, CancellationToken cancellationToken)
        {
            var abort = new TaskCompletionSource();

            using (var abortCancellationToken = CancellationTokenHelpers.FromTask(abort.Task))
                using (var combinedToken = CancellationTokenHelpers.Normalize(abortCancellationToken.Token, cancellationToken))
                {
                    var token   = combinedToken.Token;
                    var tasks   = collections.Select(q => q.TryTakeAsync(token, abort));
                    var results = await TaskShim.WhenAll(tasks).ConfigureAwait(false);

                    var result = results.FirstOrDefault(x => x.Success);
                    if (result != null)
                    {
                        return(result);
                    }
                    cancellationToken.ThrowIfCancellationRequested();
                    return(AsyncCollection <T> .FalseResult);
                }
        }