4. BlockingCollection<T>: Provides blocking and bounding capabilities for thread-safe collections that implement IProducerConsumerCollection<T>.I’ll also discuss IProducerConsumerCollection<T> interface here which defines methods to manipulate thread-safe collections intended for producer/consumer usage. This interface provides a unified representation for producer/consumer collections so that higher level abstractions such as System.Collections.Concurrent.BlockingCollection<T> can use the collection as the underlying storage mechanism.<br />ConcurrentQueue<T> <br />Represents a thread-safe first in-first out (FIFO) collection. Concurrent Queue removed Dequeue and Peek method; instead it has introduced TryPeek and TryDequeue which ensure safe retrieval of records. It doesn’t use locks at all instead it rely on Interlocked operations to achieve thread-safety.<br />These methods are follows<br />bool TryDequeue<T>(out T result); attempts to dequeue record from beginning of queue and remove it from queue.<br />bool TryPeek<T>(out T result); attempts to peek record from beginning of queue without removing it.<br />Below example is showing use of ConcurrentQueue collection object. In this example, first queue is filled up with 1000 records and then “N” method is dequeue records and sum the value<br />class SampleQueue<br /> {<br /> System.Collections.Concurrent.ConcurrentQueue<int> _concurrentQueue = new ConcurrentQueue<int>();<br /> <br /> public void FillQueue()<br /> {<br /> for (int p = 0; p < 1000; p++)<br /> _concurrentQueue.Enqueue(p);<br /> Action action = () =><br /> {<br /> N();<br /> };<br /> // Start 4 concurrent consuming actions.<br /> Parallel.Invoke(action, action,action,action);<br /> Console.WriteLine(quot;
outerSum = {0}, should be 1000quot;
, outerSum);<br /> }<br /> private void N()<br /> {<br /> int localValue;<br /> int localSum = 0;<br /> while (_concurrentQueue.TryDequeue(out localValue)) localSum++;<br /> Console.WriteLine(quot;
Localsum: {0} ThreadID: {1}quot;
, localSum, Thread.CurrentThread.ManagedThreadId);<br /> Interlocked.Add(ref outerSum, localSum);<br /> }<br />Parallel.Invoke(params Action[] actions)= Execute each of action in parallel, opens up no of thread equal to nbr of processors in computer.<br />ConcurrentDictionary<br />Represents a thread-safe collection of key-value pairs that can be accessed by multiple threads concurrently.<br />Important Methods<br />GetOrAdd<br />public TValue GetOrAdd(TKey key, TValue value);<br />public TValue GetOrAdd(TKey key, Func<TKey, TValue> valueFactory);<br />Adds a key/value pair to the System.Collections.Concurrent.ConcurrentDictionary<TKey,TValue>. If the key does not already exist.<br />Returns:<br />The value for the key. This will be either the existing value for the key if the key is already in the dictionary, or the new value if the key was not in the dictionary.<br />TryAdd<br />public bool TryAdd(TKey key, TValue value);<br />Attempts to add the specified key and value to the System.Collections.Concurrent.ConcurrentDictionary<TKey,TValue>.<br />Returns:<br />true if the key/value pair was added to the System.Collections.Concurrent.ConcurrentDictionary<TKey,TValue> successfully; otherwise, false.<br /> <br />public bool TryAdd(TKey key, TValue value);<br />TryGetValue<br />public bool TryGetValue(TKey key, out TValue value);<br />Attempts to get the value associated with the specified key from the System.Collections.Concurrent.ConcurrentDictionary<TKey,TValue>.<br />Returns:<br />true if the key was found in the System.Collections.Concurrent.ConcurrentDictionary<TKey,TValue>; otherwise, false.<br />Other methods<br />public bool TryRemove(TKey key, out TValue value);<br />public bool TryUpdate(TKey key, TValue newValue, TValue comparisonValue);<br />Example<br /> class SampleDictionary<br /> {<br /> ConcurrentDictionary<int, int> _dictionary = new ConcurrentDictionary<int, int>();<br /> public void FillDictionary()<br /> {<br /> //AddorUpdate Method<br /> _dictionary.AddOrUpdate(1, 2, new Func<int, int, int>(add));<br /> _dictionary.AddOrUpdate(1, 2, new Func<int, int, int>(add));<br /> //GetOrAdd<br /> int result = _dictionary.GetOrAdd(2, 44);<br /> //TryRemove<br /> int val = 0;<br /> _dictionary.TryRemove(1, out val);<br /> //TryUpdate<br /> //bool d= _dictionary.TryUpdate(2,34,55);<br /> }<br /> private int add(int key, int value)<br /> {<br /> return key + value;<br /> }<br /> }<br />ConcurrentBag<T><br />It is new type of collection in dotnet 4.0 which is unordered collection of objects. It’s a kind of bag in which we add and take something.<br />Important Methods<br />Add(T item): This method is use for adding object in collection.<br />Max() : Returns Maximum value from collection.<br />Min():Returns minimum value from collection.<br />TryTake(out T result): Attempts to remove and return an object from the System.Collections.Concurrent.ConcurrentBag<T>.<br />TryPeek(out T result) : Attempts to return an object from the System.Collections.Concurrent.ConcurrentBag<T> without removing it<br />ConcurrentBag<int> cb = new ConcurrentBag<int>();<br /> cb.Add(1);<br /> cb.Add(2);<br /> cb.Add(3);<br /> // Consume the items in the bag<br /> int item;<br /> while (!cb.IsEmpty)<br /> {<br /> if (cb.TryTake(out item))<br /> Console.WriteLine(item);<br /> else<br /> Console.WriteLine(quot;
TryTake failed for non-empty bagquot;
);<br /> }<br /> // Bag should be empty at this point<br /> if (cb.TryPeek(out item))<br /> Console.WriteLine(quot;
TryPeek succeeded for empty bag!quot;
);<br /> }<br />BlockingCollection<T>:<br />Provides blocking and bounding capabilities for thread-safe collections that implement IProducerConsumerCollection<T>. A blocking collection wraps any collection that implements IProducerConsumerCollection<T> and lets you Take an element from the wrapped collection — blocking if no element is available. You can also limit total size of collection which blocks producer if that size exceed.<br />Important Methods<br />Add and TryAdd<br />If you call Add method of collection it will block reading operation until adding operation done while TryAdd method is non block adding mechanism.<br />Take and TryTake methods remove items from collection.<br />CompleteAdding<br />This method enforce collection to not add item further.<br />In below code there are two tasks running in parallel, one is adding item and one is removing item from collection and block at Take method to get item. Task.WaitAll method waits for parallel executing tasks to be completed.<br />BlockingCollection<int> bc = new BlockingCollection<int>();<br /> int i = 1;<br /> // Spin up a Task to populate the BlockingCollection <br /> Task t1 = Task.Factory.StartNew(() =><br /> {<br /> while (i != 5)<br /> {<br /> bc.Add(i);<br /> Console.WriteLine(quot;
Adding {0} by task1quot;
, i);<br /> i++;<br /> }<br /> <br /> bc.CompleteAdding();<br /> });<br /> // Spin up a Task to consume the BlockingCollection<br /> Task t2 = Task.Factory.StartNew(() =><br /> {<br /> try<br /> {<br /> // Consume bc<br /> while (true) Console.WriteLine(quot;
Getting {0} : Left item :{1}quot;
,bc.Take(),bc.Count);<br /> }<br /> catch (InvalidOperationException)<br /> {<br /> // IOE means that Take() was called on a completed collection<br /> Console.WriteLine(quot;
That's All!quot;
);<br /> }<br /> });<br />Task.WaitAll(t1, t2);<br />