Thread Lock & Monitor in C# - Explained with Easy Examples!
Hey there, fellow C# coder! π Have you ever faced random data corruption in multithreading? π€― Or maybe two threads modifying a variable at the same time, causing unexpected results?
Well, that’s because of race conditions! π± But don’t worry! We can fix this using Thread Lock in C# and Thread Monitor in C#.
Today, Iβll break down both lock
and Monitor
, show you the differences, and explain when to use them. By the end, you’ll write thread-safe code like a pro! π
π What You Are Going to Learn in This Lesson?
βοΈ What is Thread Lock in C#?
βοΈ What is Thread Monitor in C#?
βοΈ Why do we need them?
βοΈ How do they prevent race conditions?
βοΈ Differences between lock
and Monitor
.
βοΈ Real-world examples and multiple code demonstrations!
π Why Do We Need Thread Locking?
Imagine two people trying to withdraw money from the same bank account at the same time.
- Person A checks the balance ($500) and tries to withdraw $400.
- At the exact same time, Person B checks the balance ($500) and tries to withdraw $300.
- Both transactions go throughβ¦ but wait, we only had $500! π±
Oops! Data inconsistency happened because two threads accessed the same resource (bank balance) simultaneously.
To prevent this, we use Thread Lock in C# and Thread Monitor in C# to ensure only one thread can access shared data at a time.
π What is lock
in C#?
The lock
keyword ensures only one thread can enter a critical section at a time.
Itβs the simplest and most commonly used way to handle thread safety.
Β
β
Syntax of lock
lock (lockObject)
{
// Critical section (Only one thread can access this block at a time)
}
π Example 1: Using lock
to Prevent Race Conditions
Letβs see how lock
helps in a multithreading scenario.
using System;
using System.Threading;
class Program
{
static int counter = 0;
static object lockObj = new object(); // Lock object
static void Increment()
{
for (int i = 0; i < 1000; i++)
{
lock (lockObj) // Only one thread can enter this block
{
counter++;
}
}
}
static void Main()
{
Thread t1 = new Thread(Increment);
Thread t2 = new Thread(Increment);
t1.Start();
t2.Start();
t1.Join();
t2.Join();
Console.WriteLine($"Final Counter Value: {counter}"); // Always 2000
}
}
β Output (Correct Now!)
Final Counter Value: 2000
π Problem solved! Without lock
, the counter value would be incorrect due to race conditions.
π΅οΈ What is Monitor
in C#?
The Monitor
class provides more fine-grained control over thread synchronization than lock
.
It allows:
βοΈ Entering the critical section (Monitor.Enter()
).
βοΈ Exiting the critical section (Monitor.Exit()
).
βοΈ Waiting for another thread (Monitor.Wait()
).
Β
β
Syntax of Monitor
Monitor.Enter(lockObject);
try
{
// Critical section
}
finally
{
Monitor.Exit(lockObject);
}
π₯ Example 2: Using Monitor
for Thread Synchronization
Letβs rewrite the previous example using Monitor instead of lock.
using System;
using System.Threading;
class Program
{
static int counter = 0;
static object lockObj = new object();
static void Increment()
{
for (int i = 0; i < 1000; i++)
{
Monitor.Enter(lockObj); // Locking the resource
try
{
counter++;
}
finally
{
Monitor.Exit(lockObj); // Always release the lock
}
}
}
static void Main()
{
Thread t1 = new Thread(Increment);
Thread t2 = new Thread(Increment);
t1.Start();
t2.Start();
t1.Join();
t2.Join();
Console.WriteLine($"Final Counter Value: {counter}");
}
}
β Output (Correct!)
Final Counter Value: 2000
π― Monitor works just like lock
, but gives more flexibility!
π€ When to Use lock
vs. Monitor
?
Feature | lock | Monitor |
---|---|---|
Simplicity | β Easy to use | β More complex |
Performance | β Slightly faster | β Slightly slower |
Exception Safety | β Handles automatically | β Must use try-finally |
Fine Control | β No | β Yes (can wait, signal, etc.) |
π Use lock
when you need simple thread safety.
βοΈ Use Monitor
when you need more control (waiting, signaling, etc.).
π Real-World Example: Ticket Booking System
Imagine an online ticket booking system ποΈ.
- If two users try to book the last ticket at the same time, both might get a successful booking confirmation.
- This is wrong!
- To prevent this, we use
lock
orMonitor
to ensure only one user can book at a time.
using System;
using System.Threading;
class TicketBooking
{
static int availableSeats = 1;
static object lockObj = new object();
static void BookTicket(string name)
{
lock (lockObj)
{
if (availableSeats > 0)
{
Console.WriteLine($"{name} booked a ticket!");
availableSeats--;
}
else
{
Console.WriteLine($"{name} failed to book. No seats available.");
}
}
}
static void Main()
{
Thread user1 = new Thread(() => BookTicket("Alice"));
Thread user2 = new Thread(() => BookTicket("Bob"));
user1.Start();
user2.Start();
user1.Join();
user2.Join();
}
}
β Output (Only one person books a ticket!)
Alice booked a ticket!
Bob failed to book. No seats available.
π₯ Boom! Problem solved! Now, only one user books the ticket.
π― Conclusion β Why This is Important?
β
Thread Lock in C# and Thread Monitor in C# prevent race conditions.
β
They ensure only one thread modifies shared data at a time.
β
Use lock
for simple thread safety.
β
Use Monitor
when you need more control over threads.
Β
π Next What?
π Great job! You now understand Thread Lock in C# and Thread Monitor in C#!
But wait, thereβs more! π
Next up: Mutex, Semaphore & SemaphoreSlim in C# β Master Thread Synchronization! π Stay tuned! π