How to Use lock in C#: Simple Thread Safety Guide
In C#, use the
lock statement to ensure that only one thread can access a block of code at a time, preventing race conditions. You provide an object as a lock token, and the code inside the lock block runs exclusively for one thread until it finishes.Syntax
The lock statement requires an object to lock on, called the lock token. The syntax is:
lock (lockObject)
{
// code to protect
}Here, lockObject is any reference type object used to control access. The code inside the braces runs exclusively by one thread at a time.
csharp
lock (lockObject)
{
// critical section code
}Example
This example shows two threads incrementing a shared counter safely using lock. Without lock, the final count may be incorrect due to race conditions.
csharp
using System; using System.Threading; class Program { private static int counter = 0; private static readonly object lockObj = new object(); static void Main() { Thread t1 = new Thread(IncrementCounter); Thread t2 = new Thread(IncrementCounter); t1.Start(); t2.Start(); t1.Join(); t2.Join(); Console.WriteLine($"Final counter value: {counter}"); } static void IncrementCounter() { for (int i = 0; i < 100000; i++) { lock (lockObj) { counter++; } } } }
Output
Final counter value: 200000
Common Pitfalls
- Locking on public or mutable objects: This can cause deadlocks or unexpected behavior. Always lock on a private, readonly object.
- Locking on
thisor string literals: Avoid locking onthisor strings because other code might lock on the same object, causing conflicts. - Long-running code inside lock: Keep the locked code short to avoid blocking other threads for too long.
- Forgetting to lock shared data: Leads to race conditions and unpredictable results.
csharp
/* Wrong way: locking on public object */ public class Example { public object LockObj = new object(); public void DoWork() { lock (LockObj) // risky if LockObj is accessible outside { // critical code } } } /* Right way: private readonly lock object */ public class SafeExample { private readonly object _lock = new object(); public void DoWork() { lock (_lock) { // critical code } } }
Quick Reference
- Use a private readonly object as lock token.
- Keep locked code short and fast.
- Never lock on
thisor strings. - Use
lockto prevent race conditions in multithreaded code.
Key Takeaways
Use the lock statement with a private readonly object to protect shared code from concurrent access.
Keep the code inside the lock block short to avoid blocking other threads.
Never lock on public objects, strings, or the current instance (this) to prevent deadlocks.
Locking ensures only one thread runs the critical section at a time, preventing race conditions.