Reader-Writer Locks in C# – The Smart Way to Handle Threads!
Hey there, C# hero! 👋 Have you ever wondered how multiple threads can read shared data safely while ensuring that only one thread can write at a time?
That’s exactly what Reader-Writer Locks in C# do! 🚀
Today, we’ll break them down in a super friendly way with real-world examples and easy-to-follow code. Let’s go! 💡
📚 What You Are Going to Learn in This Lesson?
✔️ What are Reader-Writer Locks in C#?
✔️ Why are they important for thread synchronization?
✔️ How to use ReaderWriterLockSlim in a simple program?
✔️ Real-world scenarios where they shine!
🤔 Why Do We Need Reader-Writer Locks?
Imagine this:
- You are in a library 📚. Many people can read books at the same time.
- But if someone wants to write in a book, they need exclusive access.
This is exactly how Reader-Writer Locks in Thread work!
💡 Multiple threads can read at the same time, but only one thread can write while blocking others.
🔄 What is ReaderWriterLockSlim?
ReaderWriterLockSlim is a built-in class in C# that helps optimize read-heavy operations by allowing:
➡️ Multiple readers to access the resource simultaneously.
➡️ Only one writer to modify the resource at a time.
➡️ No readers are allowed when a writer is active.
✅ Syntax of ReaderWriterLockSlim
ReaderWriterLockSlim rwLock = new ReaderWriterLockSlim();
🏆 Example 1: Basic Reader-Writer Lock in Thread
Let’s see how multiple readers can access data at the same time, but only one writer can update it.
using System;
using System.Threading;
class Program
{
static ReaderWriterLockSlim rwLock = new ReaderWriterLockSlim();
static int sharedData = 0;
static void Reader()
{
rwLock.EnterReadLock(); // Acquire read lock
Console.WriteLine($"Reader {Thread.CurrentThread.ManagedThreadId} reads value: {sharedData}");
Thread.Sleep(1000);
rwLock.ExitReadLock(); // Release read lock
}
static void Writer()
{
rwLock.EnterWriteLock(); // Acquire write lock
sharedData++;
Console.WriteLine($"Writer {Thread.CurrentThread.ManagedThreadId} updated value to: {sharedData}");
Thread.Sleep(1000);
rwLock.ExitWriteLock(); // Release write lock
}
static void Main()
{
for (int i = 0; i < 3; i++) new Thread(Reader).Start();
Thread.Sleep(500); // Ensure readers start first
new Thread(Writer).Start();
}
}
✅ Expected Output
Reader 3 reads value: 0
Reader 4 reads value: 0
Reader 5 reads value: 0
Writer 6 updated value to: 1
- Multiple readers read the value at the same time.
- The writer waits until all readers are done, then updates the value.
🎯 Why is ReaderWriterLockSlim Important?
- Better Performance – It allows multiple readers instead of blocking all threads.
- Ensures Thread Safety – Prevents data corruption.
- Useful in Read-Heavy Applications – Like databases, logging systems, or caching.
🏆 Example 2: Preventing Race Conditions with Reader-Writer Locks in Thread
Let’s simulate a race condition and fix it with ReaderWriterLockSlim.
using System;
using System.Threading;
class Program
{
static ReaderWriterLockSlim rwLock = new ReaderWriterLockSlim();
static int counter = 0;
static void IncrementCounter()
{
rwLock.EnterWriteLock();
counter++;
Console.WriteLine($"Counter updated to {counter} by Thread {Thread.CurrentThread.ManagedThreadId}");
rwLock.ExitWriteLock();
}
static void ReadCounter()
{
rwLock.EnterReadLock();
Console.WriteLine($"Thread {Thread.CurrentThread.ManagedThreadId} read counter: {counter}");
rwLock.ExitReadLock();
}
static void Main()
{
for (int i = 0; i < 3; i++) new Thread(ReadCounter).Start();
new Thread(IncrementCounter).Start();
}
}
✅ Expected Output
Thread 3 read counter: 0
Thread 4 read counter: 0
Thread 5 read counter: 0
Counter updated to 1 by Thread 6
Before the writer modifies the value, readers safely access it.
🌍 Real-World Example: Online Banking System
Imagine an online banking system.
- Multiple users check their account balance (readers).
- Only one user can update the balance at a time (writer).
✅ Code for Real-World Example
using System;
using System.Threading;
class BankAccount
{
static ReaderWriterLockSlim rwLock = new ReaderWriterLockSlim();
static int balance = 1000;
static void CheckBalance()
{
rwLock.EnterReadLock();
Console.WriteLine($"User {Thread.CurrentThread.ManagedThreadId} checked balance: ${balance}");
Thread.Sleep(500);
rwLock.ExitReadLock();
}
static void WithdrawMoney(int amount)
{
rwLock.EnterWriteLock();
if (balance >= amount)
{
balance -= amount;
Console.WriteLine($"User {Thread.CurrentThread.ManagedThreadId} withdrew ${amount}. New balance: ${balance}");
}
else
{
Console.WriteLine($"User {Thread.CurrentThread.ManagedThreadId} tried to withdraw ${amount}, but insufficient funds.");
}
rwLock.ExitWriteLock();
}
static void Main()
{
new Thread(CheckBalance).Start();
new Thread(CheckBalance).Start();
new Thread(() => WithdrawMoney(500)).Start();
new Thread(CheckBalance).Start();
}
}
✅ Expected Output
User 3 checked balance: $1000
User 4 checked balance: $1000
User 5 withdrew $500. New balance: $500
User 6 checked balance: $500
- Multiple users check their balance at the same time.
- Only one user withdraws money, ensuring accuracy.
📌 Key Takeaways
✅ ReaderWriterLockSlim allows multiple readers but only one writer.
✅ Prevents race conditions in read-heavy applications.
✅ Use in real-world cases like banking, logging, caching, and database operations.
🚀 Next What?
🎉 Awesome job! You now understand Reader-Writer Locks in C# and how they improve thread safety.
But what if we need collections that are thread-safe? 🤔
🔥 Next up: Thread-Safe Collections in C# – Keep Data Safe in Multithreading! Stay tuned! 🚀
