C# ConcurrentQueue

Introduction

The ConcurrentQueue<T> class in C# is part of the System.Collections.Concurrent namespace and represents a thread-safe, first-in, first-out (FIFO) collection of objects. It is particularly useful in scenarios where multiple threads are adding and removing items from a collection simultaneously, and you need a queue-like behavior. The ConcurrentQueue<T> is designed to be thread-safe and optimized for high concurrency.

Key Features of ConcurrentQueue

  • Thread-Safe: Supports concurrent enqueue and dequeue operations.
  • FIFO Order: Maintains elements in a first-in, first-out order.
  • High Throughput: Optimized for scenarios with high contention.
  • No Locking: Uses lightweight synchronization mechanisms to avoid locks.

Creating a ConcurrentQueue

Declaration and Initialization

You can declare and initialize a ConcurrentQueue<T> in several ways:

Example

using System;
using System.Collections.Concurrent;

namespace ConcurrentQueueExample
{
    class Program
    {
        static void Main(string[] args)
        {
            // Creating an empty ConcurrentQueue
            ConcurrentQueue<int> queue = new ConcurrentQueue<int>();

            // Adding elements to the ConcurrentQueue
            queue.Enqueue(1);
            queue.Enqueue(2);
            queue.Enqueue(3);

            // Displaying elements
            Console.WriteLine("Elements in ConcurrentQueue:");
            foreach (int item in queue)
            {
                Console.WriteLine(item);
            }
        }
    }
}

Output

Elements in ConcurrentQueue:
1
2
3

Common Operations on ConcurrentQueue

Adding Elements

  • Enqueue: Adds an element to the end of the ConcurrentQueue.
queue.Enqueue(4);

Removing Elements

  • TryDequeue: Attempts to remove and return the object at the beginning of the ConcurrentQueue. Returns true if an object was removed successfully; otherwise, false.
bool success = queue.TryDequeue(out int item);
if (success)
{
    Console.WriteLine($"Dequeued: {item}");
}
else
{
    Console.WriteLine("No items to dequeue.");
}

Peeking at Elements

  • TryPeek: Attempts to return the object at the beginning of the ConcurrentQueue without removing it. Returns true if an object was returned successfully; otherwise, false.
bool success = queue.TryPeek(out int item);
if (success)
{
    Console.WriteLine($"Peeked: {item}");
}
else
{
    Console.WriteLine("No items to peek.");
}

Checking the Collection Size

  • Count: Gets the number of elements in the ConcurrentQueue.
int count = queue.Count;
Console.WriteLine($"Count: {count}");

Iterating Through a ConcurrentQueue

You can iterate through a ConcurrentQueue using a foreach loop. However, note that the collection is thread-safe for concurrent modifications, and the snapshot taken by foreach might not reflect all concurrent changes.

Example

foreach (int item in queue)
{
    Console.WriteLine(item);
}

Practical Example

Let’s create a practical example where we use a ConcurrentQueue<T> to manage a collection of tasks executed by multiple threads, allowing them to add completed tasks to the queue.

Example

using System;
using System.Collections.Concurrent;
using System.Threading.Tasks;

namespace TaskCompletionExample
{
    class Program
    {
        static void Main(string[] args)
        {
            ConcurrentQueue<string> completedTasks = new ConcurrentQueue<string>();

            // Creating and starting multiple tasks
            Task[] tasks = new Task[5];
            for (int i = 0; i < tasks.Length; i++)
            {
                int taskId = i;
                tasks[i] = Task.Run(() => CompleteTask(completedTasks, taskId));
            }

            // Waiting for all tasks to complete
            Task.WaitAll(tasks);

            // Displaying completed tasks
            Console.WriteLine("Completed Tasks:");
            foreach (string task in completedTasks)
            {
                Console.WriteLine(task);
            }
        }

        static void CompleteTask(ConcurrentQueue<string> completedTasks, int taskId)
        {
            // Simulate some work
            Task.Delay(1000).Wait();
            string taskName = $"Task {taskId}";
            completedTasks.Enqueue(taskName);
            Console.WriteLine($"{taskName} completed.");
        }
    }
}

Output

Task 0 completed.
Task 1 completed.
Task 2 completed.
Task 3 completed.
Task 4 completed.
Completed Tasks:
Task 0
Task 1
Task 2
Task 3
Task 4

Conclusion

The ConcurrentQueue<T> class in C# provides a thread-safe, first-in, first-out (FIFO) collection of objects that is optimized for high concurrency. It supports concurrent enqueue and dequeue operations without locking, making it ideal for scenarios where multiple threads need to interact with a shared queue. Understanding how to use ConcurrentQueue<T> effectively can help you manage collections of data in multi-threaded applications.

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top