Lock keyword in C# | Thread Locking In C#

This post series we will go through the understanding of the lock keywordmonitor, mutex, and semaphore available in C#.

All of these classes provide a synchronization mechanism to protect the shared code or resources in a multithreaded application.

In C #, the Lock keyword ensures that only one thread runs at a time. The lock keyword prevents a thread from entering a critical area of ​​code while another thread is already there.

Lock in C#
Lock keyword in C#

Lock keyword in C#

Lock Statement: In C#, the locking is a synchronization mechanism that allows only one thread to access a specific piece of code or a common field at a time. In a multithreaded environment, the Lock keyword is mainly used to implement exclusive locks to avoid inconsistent results when reading and writing public variables.

Generally, the  lock  keyword is placed around a critical section of code, where we want to allow only one thread to access the resource at a time.
Any other thread is locked and cannot acquire the lock and must wait for the lock to be released.

Syntax of using lock keyword in c# 

The syntax for obtaining a mutual-exclusion lock for the specified piece of code using the lock keyword is as follows.

Lock (expression) { statement block }

 //syntax to use the lock keyword
lock (obj)
 {
   // Critical code section
 }

Example of Lock Statement In C#

In the following example, we are using the lock keyword around a critical section of code. Which allows only one thread to enter and execute the code at a time.

using System;
using System.Threading;
namespace LockStatementDemo
{
    class Program
    {
        static readonly object _lock = new object();
        static void Main(string[] args)
        {          
         // Creating threads
         Thread thread1 = new Thread(PrintCharacter);
         Thread thread2 = new Thread(PrintCharacter);
        // Executing the tasks
         thread1.Start();
         thread2.Start();

         Console.ReadLine();
      
        }
        public static void PrintCharacter()
        {
            string strArray = "Hello World";
            lock (_lock)
            {
                for (int i = 0; i < strArray.Length; i++)
                {
                    Console.Write($"{strArray[i]}");
                    //Pausing the thread execution for 2 seconds
                    Thread.Sleep(TimeSpan.FromSeconds(2));
                }
            }
            Console.Write(" ");
        }

    }
}

In the above code, we have created two separate threads thread1, and thread2 in the main method to call the static method PrintCharacter simultaneously.

Here, we are using the lock statement on the variable of type object called ‘_lock’ to acquire the exclusive lock on the  for loop  statement.
It will allow only one thread to enter into the critical section to execute the code at a time.

Let’s run the above program to see the result.

Multithreading using lock
The output of the above C# program.

In the above result, we can see that the lock statement blocked the second thread to execute the code until the first thread released the object.

Example – Multithreading Without Lock Statement

In the following example, multiple threads are executing the critical section of code simultaneously without using the lock statement.

using System;
using System.Threading;
namespace Multithreading
{
    class Program
    {    
        static void Main(string[] args)
        {          
         // Creating threads
         Thread thread1 = new Thread(PrintCharacter);
         Thread thread2 = new Thread(PrintCharacter);
        // Executing the tasks
         thread1.Start();
         thread2.Start();

         Console.ReadLine();
      
        }
        public static void PrintCharacter()
        {
            string strArray = "Hello World";
           
                for (int i = 0; i < strArray.Length; i++)
                {
                    Console.Write($"{strArray[i]}");
                    //Pausing the thread execution for 2 seconds
                    Thread.Sleep(TimeSpan.FromSeconds(2));
                }
           
            Console.Write(" ");
        }
    }
}

Multithreading without lock keyword
The output of the above program

In the above result, we can see that both thread1 and thread2 are executing the same piece of code simultaneously.

This is why we use the lock statement to implement exclusive locks to avoid inconsistent results when reading and writing public variables in a multithreaded environment.

In C#, the lock statement internally wraps the Monitor.Enter and Monitor.Exit methods, with additional try/finally block.

 lock   Monitor.Enter  +  Monitor.Exit +  try/finally 

Use Lock on a reference type rather than the value type

In the above program, we are passing an object instance as a parameter in the lock statement.

But what if we try to pass a value type variable in the lock statement rather than an object type.

unfortunately, The C# compiler will throw a compile-time error message like:
‘int’ is not a reference type as required by the lock statement.

 class Program
    {
        static int _lock;
        static void ReadFile()
        {
            lock (_lock)
            {
                // Code
            }
        }
     }
lock keyword on value type
lock keyword on the value type

Avoid using the lock keyword in the following situation

    • Avoid using lock keyword on value type
    • Avoid using ‘this‘ keyword as lock expression
    • Don’t lock the type objects

1. Avoid using lock keyword on value type

If the compiler allows you to lock a value type, it will not lock anything in the end since you will be sending a different boxed copy of the value type to the lock each time. As a result, the locks would be as if they (value types) were entirely different objects.

Use the lock keyword on reference type objects instead of value types; otherwise, you will receive a compile-time error.

2. Avoid using ‘this’ keyword as lock expression

Use private reference type variables instead of this keyword (Example: lock(this)) to avoid deadlock situations where multiple threads are waiting to start the same object.

Using this as a lock statement is also a bad practice as it will block the entire object,
All the other parts of the code will be blocked and wait to execute for no reason and may cause a performance issue.

Using this can cause problems because the instance is publicly accessible and can be accessed by multiple threads.

3. Avoid using ‘lock keyword’ on string object

String object: Avoid using lock statements on string objects, because the interned strings are essentially global in nature and may be blocked by other threads without your knowledge, which can cause a deadlock.

Conclusion

The  lock  statement is basically used to protect a shared resource from being access by the multiple threads in a multithreaded environment.

It allows only one thread to access a  critical section of code at a time to avoid the race condition.

I hope you found this post useful in learning about the use of the lock keyword in C#. Your comments, suggestions, and constructive criticism are much appreciated.

Recommended Articles

    1. C# Monitor class in multithreading with examples
    2. Multithreading in C#
    3. 10 Difference between interface and abstract class In C#
    4. C# Enum | How To Play With Enum in C#?
    5. Properties In C# with examples
    6. Generic Delegates in C# With Examples
    7. Constructors in C# with Examples
    8. C# Dictionary with Examples
    9. IEnumerable Interface in C# with examples
    10. Access Modifiers in C#

Leave a Reply