TheDeveloperBlog.com

Home | Contact Us

CSharp | Java | Python | Swift | GO | WPF | Ruby | Scala | F# | JavaScript

C# ConcurrentBag Example

This C# article shows an example of the ConcurrentBag collection. ConcurrentBag is found in System.Collections.Concurrent.

ConcurrentBag is a collection of values.

Threads must often access a single collection of values. Sometimes lookup functionality is not required. ConcurrentBag allows us to safely Add and Take results.

Example. This program is fairly useless—it shows ConcurrentBag on a single thread. The bag should be used only when multiple threads access it. In the code we show how Add, TryPeek and TryTake work.

Add: This adds an element to the inside of the ConcurrentBag. Elements are stored in the order you add them.

TryPeek: This returns, in its out parameter, the value most recently added to the bag. It does not change the bag's contents.

TryTake: This returns, in the out parameter, the most recently added element. It removes the element from the contents.

C# program that uses ConcurrentBag

using System;
using System.Collections.Concurrent;

class Program
{
    static void Main()
    {
	ConcurrentBag<int> bag = new ConcurrentBag<int>();
	bag.Add(1);
	bag.Add(2);
	bag.Add(3);

	int result;
	if (bag.TryPeek(out result))
	{
	    Console.WriteLine("TryPeek: {0}", result);
	}

	if (bag.TryTake(out result))
	{
	    Console.WriteLine("TryTake: {0}", result);
	}

	if (bag.TryPeek(out result))
	{
	    Console.WriteLine("TryPeek: {0}", result);
	}
    }
}

Output

TryPeek: 3
TryTake: 3
TryPeek: 2

The TryPeek and TryTake methods are examples of the tester-doer pattern. They return true if their goal is completed successfully. If no elements are in the bag, they will return false.

Tester-Doer

Constructor. It is possible to create a ConcurrentBag from its constructor. No calls to Add() are needed. In many programs this is probably the most useful way to populate a bag. Many programs, when starting, have known values to use.

String array: This bag uses the string type. And its constructor can be passed a string array. The bag has three elements.

String Array

C# program that creates ConcurrentBag

using System;
using System.Collections.Concurrent;

class Program
{
    static void Main()
    {
	// ... Create bag from string array.
	string[] array = { "Dot", "Net", "Perls" };
	ConcurrentBag<string> bag = new ConcurrentBag<string>(array);

	string value;
	if (bag.TryPeek(out value))
	{
	    Console.WriteLine("TryPeek: {0}", value);
	}
	Console.WriteLine("Count:   {0}", bag.Count);
    }
}

Output

TryPeek: Perls
Count:   3

Internals. The internals of ConcurrentBag are surprisingly complex. This class maintains its internal elements in a private ThreadLocalList. Each element is stored in a Node. One funny detail is that it contains private methods named Steal.

So: The ConcurrentBag, when it cannot TryTake something, will attempt to TrySteal it instead. ConcurrentBag always gets what it wants.

Also: The ConcurrentBag uses the Interlocked class to provide thread-safety, as in the TryTakeOrPeak method.

Interlocked

Summary. A ConcurrentBag is simple. This is its main advantage over similar concurrent collections such as ConcurrentDictionary. The code that uses this bag is also simple. For threading, a complex task itself, this is important.

ConcurrentDictionary