Threading Simplified: Synchronization Context - Part 14

I am here again  to continue the discussion around Threading. Today, we will discuss synchronization context and the related concepts.

Links are given below to my previous parts:

Let’s start by putting forth some questions in order to understand the concepts.

What is Synchronization Context in Multithreading and when it is used?

Synchronization Context is yet another construct to control and manage thread execution in a multi threaded environment. It is used when we want a class level locking mechanism without manually locking the individual methods or properties.

How is Synchronization Context different from other constructs like lock, mutex and semaphore?

Synchronization Context provides automatic class or object level locking whereas other constructs like lock, mutex and semaphore are designed to implement manual locking for any specific code block.

How does Synchronization Context work?

If any class is annotated with Synchronization keyword and derived from ContextBoundObject, then .NET runtime puts an object level lock on all the methods, properties and fields of a class and hence only a single thread can access the members at one point of time.

We will understand this with the help of a simple example.

Let’s begin with defining the thread unsafe class or regular class as follows.

  1. public class RegularClass  
  2. {  
  3.     List < string > nameList = newList < string > ();  
  4.     public void SetItem(string name)  
  5.     {  
  6.         nameList.Add(name);  
  7.     }  
  8.     public void PrintItems(objectthreadName)  
  9.     {  
  10.         Console.WriteLine("Thread {0} started executing PrintItems", threadName.ToString());  
  11.         Thread.Sleep(500);  
  12.         foreach(stringstrinnameList)  
  13.         Console.WriteLine(str);  
  14.         Console.WriteLine("Thread {0} finished executing PrintItems", threadName.ToString());  
  15.     }  
  16. }  
  17. class Program  
  18. {  
  19.     static void Main(string[] args)  
  20.     {  
  21.         Console.Title = "SynchronizationContext Demo";  
  22.         Threadthread1 = null;  
  23.         Threadthread2 = null;  
  24.         Threadthread3 = null;  
  25.         RegularClassrClass = newRegularClass();  
  26.         rClass.SetItem("Prakash");  
  27.         rClass.SetItem("Aradhana");  
  28.         thread1 = newThread(newParameterizedThreadStart(rClass.PrintItems));  
  29.         thread1.Start("thread1");  
  30.         thread2 = newThread(newParameterizedThreadStart(rClass.PrintItems));  
  31.         thread2.Start("thread2");  
  32.         thread3 = newThread(newParameterizedThreadStart(rClass.PrintItems));  
  33.         thread3.Start("thread3");  
  34.     }  
  35. }  
Output

run

As you can see in the output shown above even before thread1 finishes executing the PrintItems method, thread2 starts execution of the same method. Clearly,  it’s not thread safe.

Now let’s have a look at the thread safe version using Synchronization Context as follows.
  1. [Synchronization]  
  2. public class SynchronizationContexClass: ContextBoundObject  
  3. {  
  4.     List < string > nameList = newList < string > ();  
  5.     public void SetItem(string name)  
  6.     {  
  7.         nameList.Add(name);  
  8.     }  
  9.     public void PrintItems(objectthreadName)  
  10.     {  
  11.         //Same as previous example, please refer the attached demo project   
  12.         //for full source code  
  13.     }  
  14. }  
  15. class Program  
  16. {  
  17.     static void Main(string[] args)  
  18.     {  
  19.         //Same as previous example, please refer the attached demo project   
  20.         //for full source code  
  21.         SynchronizationContexClassscClass = newSynchronizationContexClass();  
  22.         scClass.SetItem("Prakash");  
  23.         scClass.SetItem("Aradhana");  
  24.         thread1 = newThread(newParameterizedThreadStart(scClass.PrintItems));  
  25.         thread1.Start("thread1");  
  26.         thread2 = newThread(newParameterizedThreadStart(scClass.PrintItems));  
  27.         thread2.Start("thread2");  
  28.         thread3 = newThread(newParameterizedThreadStart(scClass.PrintItems));  
  29.         thread3.Start("thread3");  
  30.     }  
  31. }  
Output

output

As you can see in the output shown above, that when thread1 finishes executing the PrintItems method, then only the thread2 starts the execution and so on. Clearly it's thread safe.

Summary

In this article we discussed what Synchronization Context is and illustrated with an example how it works. Although it provides an automatic class level locking and is recommended to be used only when the other manual locking mechanism like lock/ mutex/ semaphore etc. doesn’t fit in a given scenario. Generally, manual locking is considered a better option as it’s less prone to a deadlock and provides better concurrency in comparison to a class level locking achieved by Synchronization Context.

You can also download the attached demo project (SynchronizationContextDemo.zip) to go through the source code referred to in the article.

Hope you have liked the article. Look forward for your comments/ suggestions. 


Similar Articles