PROWAREtech

articles » current » dot-net » concurrentbag-explained

.NET: ConcurrentBag - What is It and How to Use It?

What a ConcurrentBag is plus example usage in C#.

The ConcurrentBag class is a thread-safe collection in C# designed for scenarios where multiple threads need to add and remove items concurrently.

But, how does ConcurrentBag compare to the ConcurrentDictionary class.

Key points about ConcurrentBag:

  1. Thread-Safety: It's designed for concurrent access from multiple threads without explicit locking.
  2. Main Operations:
    • Add(item): Adds an item
    • TryTake(out item): Attempts to remove and return an item
    • TryPeek(out item): Looks at an item without removing it
  3. Best Use Cases:
    • When multiple threads both add and remove items
    • When the order of items doesn't matter
    • In producer-consumer scenarios
  4. Important Characteristics:
    • Unordered collection (items may come out in any order)
    • Allows duplicate elements
    • Optimized for scenarios where the same thread adds and removes items

Example Code

ConcurrentBag is also very useful with threads and Parallel.For/Parallel.ForEach, not just the Task.


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

class Program
{
	static void Main()
	{
		ConcurrentBag<int> bag = new ConcurrentBag<int>();

		// Adding items to the ConcurrentBag in parallel
		Parallel.For(0, 10, i =>
		{
			bag.Add(i);
			Console.WriteLine($"Added {i}");
		});

		// Taking items out of the ConcurrentBag
		Parallel.For(0, 10, i =>
		{
			int result;
			if (bag.TryTake(out result))
			{
				Console.WriteLine($"Removed {result}");
			}
		});

		// Checking the contents of the ConcurrentBag
		foreach (var item in bag)
		{
			Console.WriteLine(item);
		}
	}
}

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

class Program
{
	static async Task Main()
	{
		// Create a new ConcurrentBag
		var bag = new ConcurrentBag<int>();

		// Example 1: Basic Operations
		bag.Add(1);  // Add single item
		bool success = bag.TryTake(out int result);  // Try to remove and retrieve item
		Console.WriteLine($"Removed item: {result}, Success: {success}");

		// Example 2: Parallel Adding
		await Task.WhenAll(
			Task.Run(() => {
				for (int i = 0; i < 1000; i++)
				{
					bag.Add(i);
				}
			}),
			Task.Run(() => {
				for (int i = 1000; i < 2000; i++)
				{
					bag.Add(i);
				}
			})
		);
		Console.WriteLine($"Total items after parallel add: {bag.Count}");

		// Example 3: Parallel Tasking
		var tasks = new List<Task>();
		for (int i = 0; i < 4; i++)
		{
			tasks.Add(Task.Run(() => {
				while (bag.TryTake(out int item))
				{
					// Process item
					Console.WriteLine($"Thread {Task.CurrentId} processed: {item}");
				}
			}));
		}
		await Task.WhenAll(tasks);

		// Example 4: Peeking at items
		var newBag = new ConcurrentBag<int> { 1, 2, 3, 4, 5 };
		if (newBag.TryPeek(out int peekedItem))
		{
			Console.WriteLine($"Peeked at item: {peekedItem}");
		}

		// Example 5: Using in a producer-consumer scenario
		var sharedBag = new ConcurrentBag<int>();

		// Producer
		var producer = Task.Run(() => {
			for (int i = 0; i < 100; i++)
			{
				sharedBag.Add(i);
				Thread.Sleep(10); // Simulate work
			}
		});

		// Consumer
		var consumer = Task.Run(() => {
			while (sharedBag.Count > 0 || !producer.IsCompleted)
			{
				if (sharedBag.TryTake(out int item))
				{
					Console.WriteLine($"Consumed: {item}");
				}
				Thread.Sleep(15); // Simulate work
			}
		});

		await Task.WhenAll(producer, consumer);
	}
}

PROWAREtech

Hello there! How can I help you today?
Ask any question

PROWAREtech

This site uses cookies. Cookies are simple text files stored on the user's computer. They are used for adding features and security to this site. Read the privacy policy.
ACCEPT REJECT