c sharp

How to Use the ConcurrentDictionary for Thread-Safe Operations in C#

Threading is a popular component for building powerful and high-performance applications. But like that old saying, “with great power, comes great responsibility”, there is a wide array of potential issues that can arise from having multiple threads accessing values.

One of the most common issues that we as developers need to worry about when creating multithreaded applications is thread safety.

Thread safety is a mechanism that protects from an application from being accessed or modified by multiple threads at the same time. This prevents the deadlocks and data corruption.

In this tutorial, we will learn how to use the “ConcurrentDictionary” class in C# to which provides a thread-safe collection of key-value pairs to use in multi-threaded application.

 C# ConcurrentDictionary

The “ConcurrentDictionary” class is part of the “System.Collections.Concurrent” namespace. It provides a thread-safe collection of key-value pairs.

This ensures that multiple threads can read and write the data to the collection without encountering into issues such as deadlocks on the entire collection.

Syntax:

public class ConcurrentDictionary<TKey,TValue> : System.Collections.Generic.ICollection<System.Collections.Generic.KeyValuePair<TKey,TValue>>, System.Collections.Generic.IDictionary<TKey,TValue>, System.Collections.Generic.IEnumerable<System.Collections.Generic.KeyValuePair<TKey,TValue>>, System.Collections.Generic.IReadOnlyCollection<System.Collections.Generic.KeyValuePair<TKey,TValue>>, System.Collections.Generic.IReadOnlyDictionary<TKey,TValue>, System.Collections.IDictionary

The TKey is the type of the keys in the dictionary and the TValue is the type of the values in the dictionary.

Concurrent Dictionary

To create a concurrent dictionary, we can basically create an instance of the “ConcurrentDictionary” class and provide the key and value types that we wish to store in the dictionary.

Take the following code for example:

using System.Collections.Concurrent;
namespace Concurrency
{
    internal class Program
    {
        static void Main(string[] args)
        {
            ConcurrentDictionary<int, string> dict = new ConcurrentDictionary<int, string>();
        }
    }
}

This creates a concurrent dictionary that holds the integer keys and string values.

Add New Items

To add new items to a concurrent dictionary, we can use the TryAdd() method. The method returns a Boolean which indicates whether the operation is successful or not.

using System.Collections.Concurrent;
namespace Concurrency
{
    internal class Program
    {
        static void Main(string[] args)
        {

            ConcurrentDictionary<int, string> dict = new ConcurrentDictionary<int, string>();
            bool status = dict.TryAdd(3306, "MySQL");
            if (status)
            {
                Console.WriteLine("success");
            }
            else
            {
                Console.WriteLine("Fail.");
            }
        }
    }
}

In the given example, we save the status of the addition operation to a variable and use it to test whether it was successful or not.

Update the Items

Similarly, we can use the TryUpdate() method to update the existing items on a concurrent dictionary. An example is as follows:

dict.TryUpdate(3306, "MySQL 8", "MySQL");

The method accepts the key that you wish to update, the new value, and the old value as parameters. Like the TryAdd() method, this also returns a Boolean value.

Fetch the Items

As you can guess, we can use the TryGetValue() method to retrieve the value of a given key in the concurrent dictionary.

using System.Collections.Concurrent;
namespace Concurrency
{
    internal class Program
    {
        static void Main(string[] args)
        {

            ConcurrentDictionary<int, string> dict = new ConcurrentDictionary<int, string>();
            dict.TryAdd(3306, "MySQL 8");
            string value;
            bool found = dict.TryGetValue(3306, out value);
            if (found)
            {
                Console.WriteLine(value);
            } else {
                Console.WriteLine("null");
            };
        }
    }

}

This should fetch the value that is associated with that and store it in a variable.

Concurrent Methods

The class also provides us with methods such as AddOrUpdate to handle the concurrent operations as follows:

dict.AddOrUpdate(9200, "Elasticsearch", (key, oldValue) => oldValue + " Elasticsearch");

In this case, the method either updates the value if it exists. Otherwise, it adds it to the collection.

Conclusion

In this tutorial, we explored how to create and work with thread-safe collection of key-value pairs using the “ConcurrentDictionary” class. Reference the docs for more details.

About the author

John Otieno

My name is John and am a fellow geek like you. I am passionate about all things computers from Hardware, Operating systems to Programming. My dream is to share my knowledge with the world and help out fellow geeks. Follow my content by subscribing to LinuxHint mailing list