/// <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); } }
/// <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); } }