C-Sharp | Java | Python | Swift | GO | WPF | Ruby | Scala | F# | JavaScript | SQL | PHP | Angular | HTML
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.
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.
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.
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.