Thread Synchronization in C#

Thread Synchronization in C# with Examples

In this article, I am going to discuss Thread Synchronization in C# with Examples. Please read our previous article where we discussed the significance of the IsAlive Property and Join Method of Thread Class in C# with Examples.

What is Thread Synchronization in C#?

Data inconsistency occurs when more than one threads access a shared resource such as in-memory data (instance or class variables) and external objects such as files at the same time. Let us understand this with an example. Consider that we have two threads Thread1 and Thread2, and both the threads access a shared resource let’s say Resource1 simultaneously. If Thread1 is trying to read data from the shared resource Resource1 when Thread2 is attempting to write data onto the shared resource Resource1, then there would be data inconsistency. Hence, in situations like this thread synchronization comes into the picture.

Synchronization in C# language is a process that allows access to shared resources smoothly. Synchronization in C# ensures that only one thread is accessing the shared resource at any given point in time, preventing other threads from doing the same at the same time.

Thread Synchronization in C# is a mechanism that is used to restrict multiple threads from accessing a shared resource at the same time. In simple words, we can also say that thread synchronization can help us to prevent multiple threads from gaining access to a shared resource simultaneously. As a result, we can have one and only one thread entering a critical section to access the shared resource at any given point in time.

Why do we need Thread Synchronization in Multithreading?

We need Thread Synchronization in Multithreading because of the following:

  1. Atomicity: Thread Synchronization supports atomicity, which ensures that multiple threads in the application are not allowed to access a shared resource concurrently to prevent data inconsistency. The code section of our program which causes data inconsistency is known as the critical section. The critical section of our program is executed atomically by one and only one thread which ensures Atomicity.
  2. Ordering: We generally want two or more threads to perform a task in a particular order or we want to restrict access to shared resources to a particular number of threads only. Usually, we don’t have much control over all this, which is one reason for race conditions. Thread synchronization provides support for ordering so that you can have control over your threads to perform the tasks as per your requirement.
What is Exclusive Lock and Non-Exclusive Lock in C#?

When a process or a thread wants to access an object, it requests a lock on that object. There are two types of locks that determine access to shared resources – Exclusive Lock and Non-Exclusive lock.

  1. Exclusive Lock: An exclusive lock makes sure that only one thread can gain access or enter a critical section at any given point in time. In C#, we can implement Exclusive Lock using the lock keyword, Monitor class, Mutex Class, and SpinLock class.
  2. Non-Exclusive Lock: Non-Exclusive locks provide read-only access to a shared resource and limit concurrency, i.e., limit the number of concurrent accesses to a shared resource. In C#, we can implement Non-Exclusive Lock using the Semaphore, SemaphoreSlim, and ReaderWriterLockSlim classes.
How Synchronization is Achieved in C#?

Synchronization in C# can be achieved in multiple ways. One of the ways to achieve Synchronization in C# is by using the feature of lock, which locks the access to a block of code within the locked object. When a thread locks an object, no other thread can access the block of code within the locked object. Only when a thread releases the lock, then it is available for other threads to access it.

In C# Language, every object has a built-in lock. By using the feature of Synchronization, we can lock an object. Locking an object can be done by using the lock keyword, and the following is the syntax to use the lock.

lock(object)
{
      //Statement1
      //Statement2
      //And more statements to be synchronized
}

So, when a thread acquires a lock over an object, then that particular thread can only access the block of statements within the locked object. Now, all the other threads wishing to access the same block of statements within the same locked object will have to wait until, the thread that has got the lock on the object, releases the lock, by exiting the block of statements.

Example without Thread Synchronization in C#:

Before we show you the example of how to use the synchronization between threads by locking an object and its practical use, let us first see what actually happens without using synchronization on executing multiple threads, which are trying to access the same resource.

In the below example, we are creating three different threads that are going to going to access the same resource i.e. in this case the shared resource is SomeMethod. The first thread to enter the method does not get its sole access, this thread executes the method for a while before it is replaced by another thread wanting to execute this method as well.

using System;
using System.Threading;

namespace ThreadStateDemo
{
    class Program
    {
        static void Main(string[] args)
        {
            Thread thread1 = new Thread(SomeMethod)
            {
                Name = "Thread 1"
            };

            Thread thread2 = new Thread(SomeMethod)
            {
                Name = "Thread 2"
            };

            Thread thread3 = new Thread(SomeMethod)
            {
                Name = "Thread 2"
            };

            thread1.Start();
            thread2.Start();
            thread3.Start();

            Console.ReadKey();
        }

        public static void SomeMethod()
        {
            Console.Write("[Welcome To The ");
            Thread.Sleep(1000);
            Console.WriteLine("World of Dotnet!]");
        }
    }
}
Output:

Example without Thread Synchronization in C#

As you can see, here we are not getting the output as expected. So, the point that you need to keep in mind is that if the shared resource is not protected in a multithreaded environment from concurrent access, then the output or the behavior of the application becomes inconsistent.

Synchronized Run of Multiple Threads in C#

In the below example, we are creating three threads that are going to access the SomeMethod, but this time access to SomeMethod will be synchronized because we are going to use the lock, to lock the object within which the method is going to be accessed by multiple threads. The first thread to enter the method gets its sole access until it exits the method, thereby avoiding the collision between multiple threads trying to access a method.

using System;
using System.Threading;

namespace ThreadStateDemo
{
    class Program
    {
        static object lockObject = new object();
        static void Main(string[] args)
        {
            Thread thread1 = new Thread(SomeMethod)
            {
                Name = "Thread 1"
            };

            Thread thread2 = new Thread(SomeMethod)
            {
                Name = "Thread 2"
            };

            Thread thread3 = new Thread(SomeMethod)
            {
                Name = "Thread 2"
            };

            thread1.Start();
            thread2.Start();
            thread3.Start();

            Console.ReadKey();
        }

        public static void SomeMethod()
        {
            // Locking the Shared Resource for Thread Synchronization
            lock (lockObject)
            {
                Console.Write("[Welcome To The ");
                Thread.Sleep(1000);
                Console.WriteLine("World of Dotnet!]");
            }
        }
    }
}
Output:

Thread Synchronization in C# with Examples

The first thread to enter the method SomeMethod over the locked object lockObject, get its sole access and once this thread has finished its execution of the method, only then it is replaced by another thread that has got the lock over the object, thereby by using the feature of synchronization by using the lock, we can avoid a conflict between threads wishing to access the same resource.

We can achieve thread synchronization in C# by using the followings. From our next article onwards, we are going to discuss the following in detail.

  1. Lock
  2. Monitor
  3. Mutex
  4. Semaphore
  5. SemaphoreSlim

Note: Thread Synchronization in C# is a mechanism that ensures that two or more concurrent processes or threads do not execute some particular section of the program, especially the critical section. In this technique, one thread executes the critical section of a program and the other thread waits until the first thread finishes execution. If a proper synchronization mechanism will be not applied then race conditions will happen.

In the next article, I am going to discuss Thread Synchronization using Lock in C# with Examples. Here, in this article, I try to explain Thread Synchronization in C# with Examples. I hope you enjoy this Thread Synchronization in C# with Examples article.

Leave a Reply

Your email address will not be published.