using System.Collections.Concurrent;
using System.Threading.Tasks;
public static void Main(string[] args)
var asyncQueue = new AsyncQueue<string>();
using (var cts = new CancellationTokenSource(3000))
Task.Run(() => asyncQueue.Enqueue("foo")),
Task.Run(() => asyncQueue.DequeueAsync(cts.Token)));
Console.WriteLine("Did not deadlock!");
catch (AggregateException ex) when (ex.InnerException is OperationCanceledException)
Console.WriteLine("Deadlocked! Add locks in order to resolve.");
public class AsyncQueue<T>
private readonly ConcurrentQueue<T> _bufferQueue;
private readonly ConcurrentQueue<TaskCompletionSource<T>> _promisesQueue;
private readonly object _syncRoot = new object();
_bufferQueue = new ConcurrentQueue<T>();
_promisesQueue = new ConcurrentQueue<TaskCompletionSource<T>>();
public void Enqueue(T item)
TaskCompletionSource<T> promise;
if (_promisesQueue.TryDequeue(out promise) &&
!promise.Task.IsCanceled &&
promise.TrySetResult(item))
if (_promisesQueue.TryDequeue(out promise) &&
!promise.Task.IsCanceled &&
promise.TrySetResult(item))
_bufferQueue.Enqueue(item);
public Task<T> DequeueAsync(CancellationToken cancellationToken)
if (!_bufferQueue.TryDequeue(out var item))
if (!_bufferQueue.TryDequeue(out item))
var promise = new TaskCompletionSource<T>();
cancellationToken.Register(() => promise.TrySetCanceled());
_promisesQueue.Enqueue(promise);
return Task.FromResult(item);