I\'m wondering if there exists an implementation/wrapper for ConcurrentQueue, similar to BlockingCollection where taking from the collection does not block, but is instead a
Here's the implementation I'm currently using.
public class MessageQueue
{
ConcurrentQueue queue = new ConcurrentQueue();
ConcurrentQueue> waitingQueue =
new ConcurrentQueue>();
object queueSyncLock = new object();
public void Enqueue(T item)
{
queue.Enqueue(item);
ProcessQueues();
}
public async Task DequeueAsync(CancellationToken ct)
{
TaskCompletionSource tcs = new TaskCompletionSource();
ct.Register(() =>
{
lock (queueSyncLock)
{
tcs.TrySetCanceled();
}
});
waitingQueue.Enqueue(tcs);
ProcessQueues();
return tcs.Task.IsCompleted ? tcs.Task.Result : await tcs.Task;
}
private void ProcessQueues()
{
TaskCompletionSource tcs = null;
T firstItem = default(T);
lock (queueSyncLock)
{
while (true)
{
if (waitingQueue.TryPeek(out tcs) && queue.TryPeek(out firstItem))
{
waitingQueue.TryDequeue(out tcs);
if (tcs.Task.IsCanceled)
{
continue;
}
queue.TryDequeue(out firstItem);
}
else
{
break;
}
tcs.SetResult(firstItem);
}
}
}
}
It works good enough, but there's quite a lot of contention on queueSyncLock
, as I am making quite a lot of use of the CancellationToken
to cancel some of the waiting tasks. Of course, this leads to considerably less blocking I would see with a BlockingCollection
but...
I'm wondering if there is a smoother, lock free means of achieving the same end