C# - Lock in Thread

Last Updated : 8 Nov, 2024

In C#, the lock statement is a mechanism that prevents multiple threads from accessing a block of code at the same time, ensuring thread safety when working with shared resources. This is particularly important in multi-threaded applications where race conditions can occur.

Example

using System;
using System.Threading;

class Program {
private static int counter = 0;
private static readonly object lockObject = new object();

static void IncrementCounter() {
for (int i = 0; i < 1000; i++) {
lock (lockObject) {
counter++;
}
}
}

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: " + counter);
}
}

Syntax

lock (object) {
// Code to be executed by a single thread
}

Lock in Thread

The lock statement is used to ensure that a block of code runs by only one thread at a time.

Syntax

lock (object) {
// Code to be executed by a single thread
}

Example

C#
using System;
using System.Threading;

class Program {
    private static int counter = 0;
    private static readonly object lockObject = new object();

    static void IncrementCounter() {
        for (int i = 0; i < 1000; i++) {
            lock (lockObject) {
                counter++;
            }
        }
    }

    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: " + counter);
    }
}

In this example, the lock statement ensures that the counter is incremented safely by multiple threads, resulting in the expected final value of 2000.

Locking Multiple Resources

When necessary, you can lock multiple resources, but it requires careful management to avoid deadlocks.

Example

C#
using System;
using System.Threading;

class Program {
    private static int counter1 = 0;
    private static int counter2 = 0;
    private static readonly object lockObject1 = new object();
    private static readonly object lockObject2 = new object();

    static void IncrementCounters() {
        lock (lockObject1) {
            counter1++;
            Thread.Sleep(10); // Simulating some work
            lock (lockObject2) {
                counter2++;
            }
        }
    }

    static void Main() {
        Thread t1 = new Thread(IncrementCounters);
        Thread t2 = new Thread(IncrementCounters);
        
        t1.Start();
        t2.Start();
        t1.Join();
        t2.Join();

        Console.WriteLine("Final Counter1: " + counter1);
        Console.WriteLine("Final Counter2: " + counter2);
    }
}

Output
Final Counter1: 2
Final Counter2: 2

Avoiding Deadlocks

Deadlocks can occur if multiple threads try to lock the same resources in a different order. To prevent this, always acquire locks in a consistent order.

Example

C#
using System;
using System.Threading;

class Program {
    private static readonly object lock1 = new object();
    private static readonly object lock2 = new object();

    static void Thread1() {
        lock (lock1) {
            Thread.Sleep(100); // Simulating some work
            lock (lock2) {
                Console.WriteLine("Thread 1 completed.");
            }
        }
    }

    static void Thread2() {
        lock (lock2) {
            Thread.Sleep(100); // Simulating some work
            lock (lock1) {
                Console.WriteLine("Thread 2 completed.");
            }
        }
    }

    static void Main() {
        Thread t1 = new Thread(Thread1);
        Thread t2 = new Thread(Thread2);
        
        t1.Start();
        t2.Start();
        t1.Join();
        t2.Join();
    }
}


Note: This example may lead to a deadlock due to the inconsistent order of locks. Proper design is needed to avoid such situations.

Conclusion

The lock statement in C# is a fundamental tool for managing concurrency in multi-threaded applications. By understanding how to use locks effectively, developers can ensure data integrity and prevent race conditions. Always be mindful of potential deadlocks when locking multiple resources.




Comment

Explore