CodeBlanks Logo Icon CodeBlanks

Summary - Concurrent collections

C# course · Expert · Lesson 30/47

Combine ConcurrentDictionary and BlockingCollection to write a work queue.

Summary - Concurrent collections

In this summary you will combine ConcurrentDictionary and BlockingCollection to write a small work queue. The producer adds tasks to a blocking queue, the consumer drains them and counts in a ConcurrentDictionary.

The methods from the last five lessons (GetOrAdd, Add, CompleteAdding, GetConsumingEnumerable and OrderBy) work together here. Keeping it single-threaded keeps the output deterministic.

Work queue design

The producer adds three tasks to a BlockingCollection<string> called work and calls CompleteAdding. The consumer drains each task with GetConsumingEnumerable and stores its name and length in a dictionary with results.GetOrAdd(item, item.Length).

You print results sorted with OrderBy(k => k.Key). This shows producer-consumer and dictionary patterns together.

Exercise Assemble the work queue

work is a BlockingCollection<string>, results a ConcurrentDictionary<string, int>. Add "apple", "banana", "cherry" to work and call CompleteAdding. Drain items with GetConsumingEnumerable and store each with results.GetOrAdd(item, item.Length). Then print $"{kvp.Key}: {kvp.Value}" sorted by OrderBy(k => k.Key).

Show example solution
Add three items with work.Add, call CompleteAdding. With GetConsumingEnumerable, do results.GetOrAdd(item, item.Length). Print with OrderBy(k => k.Key).
Example solution:
using System;
using System.Collections.Concurrent;
using System.Linq;

class Program
{
    static void Main()
    {
        var work = new BlockingCollection<string>();
        var results = new ConcurrentDictionary<string, int>();
        work.Add("apple");
        work.Add("banana");
        work.Add("cherry");
        work.CompleteAdding();
        foreach (var item in work.GetConsumingEnumerable())
        {
            results.GetOrAdd(item, item.Length);
        }
        foreach (var kvp in results.OrderBy(k => k.Key))
        {
            Console.WriteLine($"{kvp.Key}: {kvp.Value}");
        }
    }
}

Test yourself

  1. Match each collection to its role

    ConcurrentDictionary
    Thread-safe dictionary
    ConcurrentQueue
    Thread-safe FIFO
    BlockingCollection
    Producer-consumer blocking
  2. Which collection best fits a producer-consumer work queue?

    • ConcurrentDictionary
    • ConcurrentBag
    • ConcurrentStack
    • BlockingCollection
    Show answer

    BlockingCollection — Correct. BlockingCollection is designed for producer-consumer.

  3. Complete the BlockingCollection declaration

    var queue = new ____();
    Show answer
    var queue = new BlockingCollection<string>();

All lessons in Expert