Example usage:
using(var queue = new BlockingPriorityQueue<string, int>(2))
{
// capacity = 2, available = 2, count = 0
// adds element to the queue. Capacity = 2, available = 1, count = 1
await queue.EnqueueAsync("cat", 3, cancellationToken);
// adds element to the queue. Capacity = 2, available = 0, count = 2
await queue.EnqueueAsync("lion", 1);
// forces add element to the queue even if it's full. Capacity = 2, available = 0, count = 3
queue.ForceEnqueue("dog", 2);
// takes "lion" element from the queue. "lion" has highest priority. Capacity = 2, available = 0, count = 2
var element1 = await queue.DequeueAsync();
// takes "dog" element from the queue. "dog" has highest priority. Capacity = 2, available = 1, count = 1
var element2 = await queue.DequeueAsync();
// adds element to the queue. Capacity = 2, available = 0, count = 2
await queue.EnqueueAsync("bee", 3);
// waits 10 seconds for place in the queue.
await queue.EnqueueAsync("butterfly", 1, TimeSpan.FromSeconds(10), cancellationToken);
// In this place:
// If any other task dequeue an element (next is "cat") during 10 seconds then "butterfly" will be added to the queue.
// If any other task don't dequeue an element during 10 seconds TimoutException occurs.
// If any other task during 10 seconds call a cancellationTokenSource.Cancel() metod then OperationCancelledException occurs.
}
Please, note that for better performance, the Enqueue and Dequeue methods are not atomic to each other but still thread safe.