One of the most difficult tasks related to concurrent programming in C# and .Net 3.5 is sharing collections, arrays, or lists between many tasks running at the same time. Besides, the complexity increases when these concurrent tasks need to add and/or remove items from them. Doing this safely involves a great control of coordination data structures and the efficient use of precise locks.
One of the most well-known examples is a producer-consumer scheme. On one side, a producer, running in one thread, must add elements to a collection, array or list. On the other side, a producer, running concurrently in another thread, must remove elements from the same collection, array or list. Handling these situations is indeed very complex for the most brave developers and software engineers.
Luckily, the June 2008 CTP (Community Technology Preview) of Parallel Extensions to the .Net Framework added very interesting high-level coordination data structures and thread-safe collections. The result is amazing: the producer-consumer scheme complexity reduced to a minimum.
Using these amazing high-level thread-safe collections and a good design, it is possible to add and remove items from collections letting Parallel Extensions manage the necessary locks and low-level coordination stuff. The design is simplified and the code is easier to read. The concurrent collections manage the complex work and the developers focus in what they need to do using high levels of concurrency safely.
These usage of these concurrent collections imply a coordination cost, but they are very easy to use and they avoid lots of head-aches. Believe me.
These are the three concurrent collections initially added by June 2008 CPT, which are also going to be available as part of .Net 4.0 in Visual Studio 2010:
- System.Threading.Collections.BlockingCollection: Provides blocking and bounding capabilities.
- System.Threading.Collections.ConcurrentQueue: Represents a variable size first-in-first-out (FIFO) collection.
- System.Threading.Collections.ConcurrentStack: Represents a variable size last-in-first-out (LIFO) collection.
They are included in the System.Threading.Collections namespace and they implement the common System.Threading.Collections.IConcurrentCollection interface. Using them, you can easily handle many concurrent tasks running their threads adding and removing elements from a thread-safe shared collection. Hence, it is easier than ever to create multiple chained producer-consumer schemes taking full advantage of 4 or 8 cores. Besides, it is possible to have multiple threads adding elements and multiple threads removing elements, concurrently. For example, in a ConcurrentQueue, the items can be added safely using the Enqueue method and they can be safely removed using the TryDequeue method.
There are three new structures to be added in .Net 4.0: ConcurrentBag, ConcurrentLinkedList, and ConcurrentLinkedListNode. I haven't had the opportunity to work with them yet. I'll tell you about them in another post.
It sounds easy. It is. However, there are many other considerations to take into account, related to concurrency, immutability and thread-safe code. Nevertheless, you'll love these concurrent collections in .Net 4.0.