using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Threading.Tasks;
public static void Main()
EnqueueAndTryDequeue_ConcurrentAccess_Successful();
EnqueueAndTryDequeue_SingleElement_Successful();
TryDequeue_EmptyQueue_ReturnsFalse();
EnqueueAndTryDequeue_MultipleElementsInOrder_Successful();
EnqueueAndTryDequeue_MultipleElementsInReverseOrder_Successful();
public class ConcurrentPriorityQueue<TElement, TPriority> where TPriority : IComparable<TPriority>
public ConcurrentDictionary<TPriority, ConcurrentQueue<TElement>> Queues { get; private set; } = new();
public bool IsEmpty { get { return !Queues.Any(q => q.Value.Any()); } }
public void Enqueue(TElement element, TPriority priority)
if (!Queues.TryGetValue(priority, out var queue))
Queues[priority] = queue;
public bool TryDequeue(out TElement? element, out TPriority? priority)
element = default(TElement);
priority = default(TPriority);
var highestPriority = Queues.Keys.Max();
var highestPriorityQueue = Queues[highestPriority];
highestPriorityQueue.TryDequeue(out element);
if (!highestPriorityQueue.Any())
Queues.Remove(highestPriority, out _);
priority = highestPriority;
public TElement Dequeue()
throw new InvalidOperationException("PriorityQueue is empty.");
TryDequeue(out var element, out _);
throw new InvalidOperationException("PriorityQueue is empty.");
var highestPriority = Queues.Keys.Max();
Queues[highestPriority].TryPeek(out var peeked);
public TElement? TryPeek()
return Queues.Sum(q => q.Value.Count);
public static void EnqueueAndTryDequeue_SingleElement_Successful()
var queue = new ConcurrentPriorityQueue<int, int>();
queue.TryDequeue(out var element, out var priority);
priority.Should().Be(10);
public static void TryDequeue_EmptyQueue_ReturnsFalse()
var queue = new ConcurrentPriorityQueue<int, int>();
var result = queue.TryDequeue(out _, out _);
result.Should().BeFalse();
public static void EnqueueAndTryDequeue_MultipleElementsInOrder_Successful()
var queue = new ConcurrentPriorityQueue<int, int>();
queue.TryDequeue(out var element1, out var priority1);
queue.TryDequeue(out var element2, out var priority2);
queue.TryDequeue(out var element3, out var priority3);
priority1.Should().Be(40);
priority2.Should().Be(30);
priority3.Should().Be(20);
public static void EnqueueAndTryDequeue_MultipleElementsInReverseOrder_Successful()
var queue = new ConcurrentPriorityQueue<int, int>();
queue.TryDequeue(out var element3, out var priority3);
queue.TryDequeue(out var element2, out var priority2);
queue.TryDequeue(out var element1, out var priority1);
priority3.Should().Be(40);
priority2.Should().Be(30);
priority1.Should().Be(20);
public static void EnqueueAndTryDequeue_ConcurrentAccess_Successful()
var queue = new ConcurrentPriorityQueue<int, int>();
var tasks = new List<Task>();
for (int i = 0; i < numThreads; i++)
for (int j = 0; j < numElements; j++)
for (int i = 0; i < numThreads; i++)
for (int j = 0; j < numElements; j++)
if (queue.TryDequeue(out var element, out var priority))
Task.WhenAll(tasks).Wait();
queue.Count().Should().Be(0);