articles

Home / DeveloperSection / Articles / Concurrent Collections in C#

Concurrent Collections in C#

Anupam Mishra19306 23-Jan-2016

 In C#, traditional collection classes are using with a lock, but concurrent collection classes are lock free. So, it will often use in parallel programming for performance concern. ConcurrentDictionaryruns three times faster than Dictionary.

The concurrent collections can sometimes be useful in general multithreading when we need a thread-safe collection. However, there are some conditions:

  • The concurrent collections are using in highly concurrent scenarios.
  • A thread-safe collection doesn’t guarantee that the code using it will be thread-safe.
  • If we enumerate over a concurrent collection while another thread is modifying
  • it, no exception is thrown.
  • There’s no concurrent version of List<T> in concurrent collections.
  • The concurrent stack, queue, and bag classes are implemented internally with
  • linked lists.

In Framework 4.0 provides a set of new collections in the

System.Collections.Concurrent namespace. All of these are fully thread-safe:

·         ConcurrentStack<T>

·         ConcurrentQueue<T>

·         ConcurrentBag<T>

·         BlockingCollection<T>

·         ConcurrentDictionary<Tkey,TValue>

 

     

IProducerConsumerCollection<T>

In the IProducerConsumerCollection<T> interface defines methods to manipulate

thread-safe collections intended for producer/consumer usage. A

producer/consumer collections which is the two primary use cases. These are:

  • Adding an element (“producing”)
  • Retrieving an element (“consuming”)

The IProducerConsumerCollection<T> interface are implementing three classes

these are follows:

ConcurrentStack<T>

ConcurrentQueue<T>

ConcurrentBag<T>


This interface also extends ICollection interface for adding the following methods:

bool TryAdd (T item);

bool TryTake (out T item);

 

The TryAdd and TryTake methods test add and remove operation for eliminating


the need of lock. If the collection is empty TryTake returns false otherwise, TryAdd


always succeeds and returns true.


ConcurrentBag<T>

ConcurrentBag<T> stores an unordered collection of objects (it allows duplicates contents). ConcurrentBag<T>  is prefer in situations when we do not care which element we get when calling TryTake or Take.

The benefit of  ConcurrentBag<T> over a concurrent queue or stack is that a bag’s Add method suffers almost no contention when called by many threads at once. A concurrent bag would be a poor choice for a producer/consumer queue, because elements are added and removed by different threads.

BlockingCollection<T>

If we call TryTake on any of the producer/consumer collections we discussed previously and the collection is empty, the method returns false. Sometimes it would be more useful in this scenario to wait until an element is available. Rather than overloading the TryTake methods

Here we use BlockingCollection<T> (exception handling aside) in a program:

classAddTakeDemo
{   publicstaticvoid BC_AddTakeCompleteAdding()   {      using (BlockingCollection<string> bc = newBlockingCollection<string>())
        {
            // Spin up a Task to populate the BlockingCollection
            using (Task t1 = Task.Factory.StartNew(() =>
            {
                for (int i = 1; i <=10; i++)
                {
                    bc.Add("HI Guest "+i);
                }
                bc.CompleteAdding();
            }))
            {
                // Spin up a Task to consume the BlockingCollection
                using (Task t2 = Task.Factory.StartNew(() =>
                {
                    try
                    {
                        // Consume consume the BlockingCollection
                        while (true) Console.WriteLine(bc.Take());
                    }
                    catch (InvalidOperationException)
                    {
                        // An InvalidOperationException means that Take() was called on a completed collection
                        Console.WriteLine("That's All. Everything is Ok!");
                    }
                }))
                    Task.WaitAll(t1, t2);
            }   }    }
}
classBlockingCollectionEx
{    staticvoid Main(){   Console.WriteLine(@" Let's try to use Concurrent collection");
   AddTakeDemo.BC_AddTakeCompleteAdding();       Console.ReadKey();    }
}

Output:


Concurrent Collections in C#

 

Because we didn’t pass anything into Blocking Collection’s constructor, it instantiated a concurrent queue automatically.

For details we see also:
·         Parallel Programming in C#
·         Synchronization in C#
·         https://msdn.microsoft.com/en-us/library/dd287147%28v=vs.110%29.aspx
·         https://msdn.microsoft.com/en-us/library/dd267331%28v=vs.110%29.aspx

·         https://msdn.microsoft.com/en-us/library/dd381779%28v=vs.110%29.aspx


Updated 10-Aug-2020

Leave Comment

Comments

Liked By