Article Categories
- All Categories
-
Data Structure
-
Networking
-
RDBMS
-
Operating System
-
Java
-
MS Excel
-
iOS
-
HTML
-
CSS
-
Android
-
Python
-
C Programming
-
C++
-
C#
-
MongoDB
-
MySQL
-
Javascript
-
PHP
-
Economics & Finance
What is the difference between Monitor and Lock in C#?
Both Monitor and lock provide thread synchronization mechanisms in C#, but they serve different purposes. The lock statement is a simplified syntax that internally uses Monitor.Enter and Monitor.Exit with proper exception handling. Monitor offers more advanced features for complex threading scenarios.
Syntax
Following is the syntax for using lock statement −
lock (lockObject) {
// critical section code
}
Following is the syntax for using Monitor class −
Monitor.Enter(lockObject);
try {
// critical section code
} finally {
Monitor.Exit(lockObject);
}
Using Lock Statement
The lock statement provides a simple way to ensure thread safety for basic synchronization scenarios −
using System;
using System.Threading.Tasks;
class Program {
static object _lock = new object();
static int Total = 0;
public static void Main() {
Task[] tasks = new Task[5];
for (int i = 0; i < 5; i++) {
tasks[i] = Task.Run(() => AddOneHundredLock());
}
Task.WaitAll(tasks);
Console.WriteLine("Final Total using lock: " + Total);
}
public static void AddOneHundredLock() {
for (int i = 1; i <= 100; i++) {
lock (_lock) {
Total++;
}
}
}
}
The output of the above code is −
Final Total using lock: 500
Using Monitor Class
The Monitor class provides the same functionality as lock but with explicit control over the synchronization mechanism −
using System;
using System.Threading;
using System.Threading.Tasks;
class Program {
static object _lock = new object();
static int Total = 0;
public static void Main() {
Task[] tasks = new Task[5];
for (int i = 0; i < 5; i++) {
tasks[i] = Task.Run(() => AddOneHundredMonitor());
}
Task.WaitAll(tasks);
Console.WriteLine("Final Total using Monitor: " + Total);
}
public static void AddOneHundredMonitor() {
for (int i = 1; i <= 100; i++) {
Monitor.Enter(_lock);
try {
Total++;
} finally {
Monitor.Exit(_lock);
}
}
}
}
The output of the above code is −
Final Total using Monitor: 500
Advanced Monitor Features
The Monitor class provides additional methods for advanced threading scenarios −
using System;
using System.Threading;
using System.Threading.Tasks;
class ProducerConsumer {
static object _lock = new object();
static bool dataReady = false;
public static void Main() {
Task producer = Task.Run(() => Producer());
Task consumer = Task.Run(() => Consumer());
Task.WaitAll(producer, consumer);
}
static void Producer() {
Monitor.Enter(_lock);
try {
Console.WriteLine("Producer: Creating data...");
Thread.Sleep(2000);
dataReady = true;
Console.WriteLine("Producer: Data ready, notifying consumer");
Monitor.Pulse(_lock);
} finally {
Monitor.Exit(_lock);
}
}
static void Consumer() {
Monitor.Enter(_lock);
try {
while (!dataReady) {
Console.WriteLine("Consumer: Waiting for data...");
Monitor.Wait(_lock);
}
Console.WriteLine("Consumer: Processing data");
} finally {
Monitor.Exit(_lock);
}
}
}
The output of the above code is −
Consumer: Waiting for data... Producer: Creating data... Producer: Data ready, notifying consumer Consumer: Processing data
Comparison
| Feature | lock Statement | Monitor Class |
|---|---|---|
| Syntax | Simple, concise | Verbose, explicit |
| Exception Safety | Automatic try-finally | Manual try-finally required |
| Timeout Support | No | Yes (TryEnter) |
| Wait/Pulse | No | Yes |
| Use Cases | Basic synchronization | Advanced threading scenarios |
Conclusion
Use lock for simple thread synchronization as it provides cleaner syntax and automatic exception handling. Choose Monitor when you need advanced features like timeouts, conditional waiting with Wait() and Pulse(), or more granular control over the synchronization mechanism.
