The lock in C# can be used to get a mutual-exclusion lock on a block of code, ensuring that only one thread can run it at once.
Any thread that wishes to run the same piece of code must wait until the thread holding the lock has finished running it.
private static readonly Object myObj = new Object(); lock(myObj ) { only one thread at a time }
The above syntax can lock the piece of code in the C# language.
Program to Implement the lock in C#
I am using the Stack collection to store the number from one to ten and display the number using multiple threads.
using System; using System.Collections.Generic; using System.Threading; namespace Demo.App { static class Program { private static readonly Stack<int> Numbers = new Stack<int>(); static void Main(string[] args) { for (var i = 1; i < 11; i++) { Numbers.Push(i); } var thread1 = new Thread(PrintNumber); var thread2 = new Thread(PrintNumber); thread1.Start(); thread2.Start(); Console.ReadKey(); } private static void PrintNumber() { while (Numbers.Count > 0) { Console.WriteLine(Numbers.Pop()); } } } }
PrintNumber method has a logic to pop the number from the stack and print the number. And, PrintNumber method is called from two diffrent threads t1 and t2 both of the threads will try to pop the number and log into the console.
Both threads will attempt to log the numbers in the console. Therefore, every time you execute the program, there won’t be any order. Numbers will be arranged differently.
This issue can be resolved by using the lock, ensuring that only one thread attempts to print the number at a time.
using System; using System.Collections.Generic; using System.Threading; namespace Demo.App { static class Program { private static readonly object obj = new object(); private static readonly Stack<int> Numbers = new Stack<int>(); static void Main(string[] args) { for (var i = 1; i < 11; i++) { Numbers.Push(i); } var thread1 = new Thread(PrintNumber); var thread2 = new Thread(PrintNumber); thread1.Start(); thread2.Start(); Console.ReadKey(); } private static void PrintNumber() { lock (obj) { while (Numbers.Count > 0) { Console.Write(Numbers.Pop()+", "); } } } } }
Let’s try running the code multiple times to determine the sequence of the printed numbers.
This was one of the use cases for implementing the lock in C#. However, you can use it anywhere in the code where you want to lock the code only for one thread at a time.
Singleton design pattern using lock in C#
A Singleton design pattern is used when we want to restrict the instance to class to be created only once in the entire lifecycle of the program.
There are multiple ways of achieving the singleton instance of the class. However, the older way of achieving this is shown below.
using System; namespace Demo.App { public class Logger { private static readonly object obj = new object(); private Logger() { } private static Logger _logger; public static Logger Instance { get { lock (obj) { if (_logger == null) { _logger = new Logger(); } return _logger; } } } public void Log(string message) { Console.WriteLine(message); } } }
Implementing the singleton using the single lock might not work why?
- Assume that two threads T1 and T2 are calling
Instance
property concurrently. - Thread T1 has checked the null condition on line 19 and entered inside if block as no instance has been created yet.
- Now T1 is inside the if condition, but it has not created an instance yet. At the same time, another thread T2 reaches the null condition on line 19. As the instance is still null, T2 also enters the if condition.
- Now both threads will create instances on line 21 which will break the singleton design pattern.
To avoid this, we can implement the double lock for singleton instance creation. You just need to put one more null check.
public static Logger Instance { get { if (_logger == null) { lock (obj) { if (_logger == null) { _logger = new Logger(); } return _logger; } } return null; } }
Conclusion
In this article, we attempted to grasp the knowledge of keyword lock in C#. What it is, how to use it, etc. We created a quick application that employs the lock keyword to prevent several threads from accessing the same line of code. We also used the keyword lock to build the singleton design pattern.
Comments are closed.