C#

ConcurrentQueue in C# – Introduction and Examples

C# ConcurrentQueue is a thread-safe collection class. It is introduced in .NET 4.0 with other concurrent collection classes. It provides a thread-safe First-In-First-Out (FIFO) data structure. You can read more about Queue here. ConcurrentQueue exists in System.Collections.Concurrent namespace

ConcurrentQueue is a wrapper around generic Queue class. Queue class also provides FIFO data structure but it is not safe to use with multi-threading environment. To provide thread-safety, we have to implement locking around Queue methods which is always error prone. To simplify things ConcurrentQueue class is introduced so that developer can use this class in multi-threading without implementing any locking mechanism.

Create ConcurrentQueue Instance

ConcurrentQueue is a generic class. We can use this with any other data-type. Below is the example of creating an instance.

ConcurrentQueue<int> coll = new ConcurrentQueue<int>();

If we want to copy existing collection into our ConcurrentQueue class then we have to use second constructor. In the second constructor we can pass any collection class which implements the IEnumerable interface. Below is the example.

List<int> ints = new List<int>();
ints.Add(1);
ints.Add(2);

ConcurrentQueue<int> coll = new ConcurrentQueue<int>(ints);

Add Items in ConcurrentQueue

It provides an Enqueue method to add any item at the end of the queue. Enqueue takes the argument which data type matches with the type argument. Below is the example.

ConcurrentQueue<int> coll = new ConcurrentQueue<int>();
coll.Enqueue(1);
coll.Enqueue(2);
coll.Enqueue(3);
coll.Enqueue(4);

It is only method available to add item to ConcurrentQueue. Enqueue method does not have any other overloaded methods.

Retrieve/Remove Single Item

For retrieving items, we have two methods.

  1. TryPeek
  2. TryDequeue

TryPeek Method

TryPeek method tries to get an item from the ConcurrentQueue without removing item from the list. It returns true if operation is successful otherwise returns false. It returns the item into an out parameter. Below is the example.

ConcurrentQueue<int> coll = new ConcurrentQueue<int>();
coll.Enqueue(1);
coll.Enqueue(2);
coll.Enqueue(3);
coll.Enqueue(4);

int item;
bool isSuccessful = coll.TryPeek(out item);
Console.WriteLine(isSuccessful); //Returns True
Console.WriteLine(item);    //Return "1"

As TryPeek does not remove an item from the queue, it returns the same item again an again.

TryDequeue Method

TryDequeue method tries to get an item from the ConcurrentQueue, but it removes item from the list. It also returns true if operation is successful other returns false. It returns the item into an out parameter. Below is the example.

ConcurrentQueue<int> coll = new ConcurrentQueue<int>();
coll.Enqueue(1);
coll.Enqueue(2);
coll.Enqueue(3);
coll.Enqueue(4);

int item;
bool isSuccessful = coll.TryDequeue(out item);  
Console.WriteLine(isSuccessful); //Returns True
Console.WriteLine(item);    //Return "1"

isSuccessful = coll.TryDequeue(out item);
Console.WriteLine(isSuccessful); //Returns True
Console.WriteLine(item);    //Return "2"

In the above example, when we dequeue an item first time it returns “1” item in the out parameter. When we again use dequeue method, it returns the second item inserted in the queue that is “2”.

Difference between TryPeek and TryDequeue methods

In the below example, I have used both TryPeek and TryDequeue methods. Both method works same, TryDequeue method removes an item from the list and TryPeek does not remove an item from the list.

int item;

ConcurrentQueue<int> coll = new ConcurrentQueue<int>();
coll.Enqueue(1);
coll.Enqueue(2);
coll.Enqueue(3);
coll.Enqueue(4);

coll.TryPeek(out item); //returns "1"
coll.TryPeek(out item); //returns "1"

coll.TryDequeue(out item); //returns "1"
coll.TryDequeue(out item); //returns "2"

coll.TryPeek(out item); //returns "3"
coll.TryDequeue(out item); //returns "3"
coll.TryDequeue(out item); //returns "4"

We call TryPeek method again and again, it returns “1” item. We use dequeue, it removes “1” item from the list and gives it in out parameter. When we again use dequeue, it returns “2” item and remove it from queue. When we again call TryPeek method, it returns “3” item. In the next TryDequeue method, it returns “3” and “4” items.

Retrieve all items

To retrieve all items, we can use ConcurrentQueue in for each loop. Below is the example.

ConcurrentQueue<int> coll = new ConcurrentQueue<int>();
coll.Enqueue(1);
coll.Enqueue(2);
coll.Enqueue(3);
coll.Enqueue(4);

foreach (var col in coll)
{
    Console.WriteLine(col);
}
// Output:
// 1
// 2
// 3
// 4

Note: Enumeration in ConcurrentQueue is thread-safe.

In the below example, we have taken two tasks. First task is adding new items to the queue and second task is enumerating items.

ConcurrentQueue<int> coll = new ConcurrentQueue<int>();


Task t1 = Task.Factory.StartNew(() =>
    {
        for (int i = 0; i < 100; ++i)
        {
            coll.Enqueue(i);
            Thread.Sleep(100);
        }
    });

Task t2 = Task.Factory.StartNew(() =>
    {
        Thread.Sleep(300);
        foreach (var item in coll)
        {
            Console.WriteLine(item);
            Thread.Sleep(150);
        }
    });

try
{
    Task.WaitAll(t1, t2);
}
catch (AggregateException ex) // No exception
{
    Console.WriteLine(ex.Flatten().Message);
}

Update item

ConcurrentQueue does not provide any method to update an item. We have to dequeue that item and add it again.

Count all Items

ConcurrentQueue provides a Count method. It returns the total number of items currently exists in queue. Below is the example.

ConcurrentQueue<int> coll = new ConcurrentQueue<int>();
coll.Enqueue(1);
coll.Enqueue(2);
coll.Enqueue(3);
coll.Enqueue(4);

int count = coll.Count(); //returns 4

IsEmpty Property

IsEmpty property returns true, if ConcurrentQueue is empty otherwise returns false. Below is the example.

ConcurrentQueue<int> coll = new ConcurrentQueue<int>();

bool isEmpty = coll.IsEmpty; //returns True

coll.Enqueue(1);
coll.Enqueue(2);
coll.Enqueue(3);
coll.Enqueue(4);

isEmpty = coll.IsEmpty;  //Returns False

Copy ConcurrentQueue to Array

It provides a ToArray() method which copies the items in the queue to the new array. 

ConcurrentQueue<int> coll = new ConcurrentQueue<int>();
coll.Enqueue(1);
coll.Enqueue(2);
coll.Enqueue(3);
coll.Enqueue(4);

int[] array = coll.ToArray();
foreach(int i in array)
{
    Console.WriteLine(i);
}

//Output:
// 1
// 2
// 3
// 4

Final Words

ConcurrentQueue is a useful collection class when we have to use queue data structure in multiple threads. It internally managed the locking, and removes the burden of managing synchronization from the developer.