Locking in C#

Thread Synchronization Using Locking in C#

In this article, I am going to discuss Thread Synchronization using Locking in C# with Examples. Please read our previous article where we discussed Thread Synchronization in C# with Examples.

  1. What happened when accessing shared resources in a single-thread application?
  2. What happened when accessing shared resources in a multi-thread application?
  3. Understanding the Locking Mechanism.
  4. How do Protect the shared resources in a multithread environment from concurrent access?
Why do we need to Protect the Shared Resources in Multithreading in C#?

In a multithreading application, it is very important for us to handle multiple threads for executing critical section code. For example, if we have a shared resource and if multiple threads want to access the shared resource then we need to protect the shared resource from concurrent access otherwise we will get some inconsistent output.

In C#, we can use lock and Monitor to provide thread safety in a multithreaded application. Both lock and monitor provide a mechanism that ensures that only one thread is executing the critical section code at any given point in time to avoid any functional breaking of code.

In this article, I am going to discuss how to protect the shared resource in a multithread environment using the lock and in the next article, I am going to discuss how to do the same thing using the Monitor in C#.

Accessing a Shared Resource in a Single-Threaded Environment in C#:

Before understanding lock to protect the resource in a multithread environment in C#, let us first understand the problem if we will not protect the shared resource. In the below example, we have a shared resource i.e. DisplayMessage() method and we call that method three times from the Main method as shown below.

using System.Threading;
using System;
namespace ThreadingDemo
{
    class Program
    {
        static void Main(string[] args)
        {
            DisplayMessage();
            DisplayMessage();
            DisplayMessage();

            Console.Read();
        }

        static void DisplayMessage()
        {
            Console.Write("[Welcome to the ");
            Thread.Sleep(1000);
            Console.WriteLine("world of dotnet!]");
        }
    }
}
Output:

Accessing a Shared Resource in a Single-Threaded Environment in C#

As the above program is a single-threaded program, so we got the output as expected. Let us see what happens if we access the shared resources in a multithreaded environment.

Accessing a Shared Resource in a Multithreaded Environment in C#:

In the below example, we created three different threads and then invoke the same DisplayMessage() method using all these three threads.

using System.Threading;
using System;
namespace ThreadingDemo
{
    class Program
    {
        static void Main(string[] args)
        {
            Thread t1 = new Thread(DisplayMessage);
            Thread t2 = new Thread(DisplayMessage);
            Thread t3 = new Thread(DisplayMessage);

            t1.Start();
            t2.Start();
            t3.Start();

            Console.Read();
        }

        static void DisplayMessage()
        {
            Console.Write("[Welcome to the ");
            Thread.Sleep(1000);
            Console.WriteLine("world of dotnet!]");
        }
    }
}
Output:

Accessing a Shared Resource in a Multithreaded Environment 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.

How to Protect a Shared Resource in a Multithread Environment from Concurrent Access in C#?

We can protect the shared resources in a multithread environment from concurrent access by using the concept Monitor and locking. Let us see how to protect the shared resource using locking in C# and see the output. In the below example, we create one object i.e _lockObject, and then we created a block using the lock keyword. To the lock keyword, we pass _lockObject, and the section or block or particular resource that you want to protect should be placed inside the lock block which is shown in the below example.

using System.Threading;
using System;
namespace ThreadingDemo
{
    class Program
    {
        static void Main(string[] args)
        {
            Thread t1 = new Thread(DisplayMessage);
            Thread t2 = new Thread(DisplayMessage);
            Thread t3 = new Thread(DisplayMessage);

            t1.Start();
            t2.Start();
            t3.Start();

            Console.Read();
        }

        private static object _lockObject = new object();
        static void DisplayMessage()
        {
            lock(_lockObject)
            {
                Console.Write("[Welcome to the ");
                Thread.Sleep(1000);
                Console.WriteLine("world of dotnet!]");
            }
        }
    }
}

Now run the application and see the output as expected as shown below.

How to Protect a Shared Resource in a Multithread Environment from Concurrent Access in C#?

The section or block or particular resource that you want to protect should be placed inside the lock block. Let us understand this with an example. In the below example, we are only protecting the shared Count variable from concurrent access.

using System.Threading;
using System;
namespace ThreadingDemo
{
    class Program
    {
        static int Count = 0;

        static void Main(string[] args)
        {
            Thread t1 = new Thread(IncrementCount);
            Thread t2 = new Thread(IncrementCount);
            Thread t3 = new Thread(IncrementCount);

            t1.Start();
            t2.Start();
            t3.Start();

            //Wait for all three threads to complete their execution
            t1.Join();
            t2.Join();
            t3.Join();

            Console.WriteLine(Count);
            Console.Read();
        }

        private static object _lockObject = new object();
        static void IncrementCount()
        {
            for (int i = 1; i <= 1000000; i++)
            {
                //Only protecting the shared Count variable
                lock (_lockObject)
                {
                    Count++;
                }
            }
        }
    }
}

When you run the above program, it will give you the output as expected as 3000000.

Here, in this article, I try to explain Thread Synchronization using Locking in C# with Examples. In the next article, I am going to discuss How to Protect a Shared Resource in a Multithread Environment using Monitor in C# with examples. I hope you enjoy this Thread Synchronization using Locking in C# with Examples article.

1 thought on “Locking in C#”

Leave a Reply

Your email address will not be published.