Mutex(lock) with C# example

In previous blog posts, we've observed that Threads/Tasks have the capability to run concurrently (more accurately, pseudo-concurrently). Additionally, we've explored how it's the responsibility of the operating system to manage thread scheduling. There is a common problem when multiple threads/tasks are accessing a common resource.

Problem

Consider a scenario where we have two tasks: one generates a star pattern in the console, while the other produces a hash pattern. Since the operating system handles task scheduling, we lack control over the order in which tasks execute. Consequently, during the creation of a pattern, interruption may occur, resulting in the drawing of an interleaved star and hash pattern. Such unpredictability is not aligned with our intentions.

Problem Demonstration

The below code prints star and hash patterns.

  • PrintStartPattern prints start pattern

  • PrintHashPattern prints hash pattern

  • These two methods are run from 2 different tasks

var t1 = Task.Run(() => { 
    for(int i = 0; i < 3; i++) {
        PrintStarPattern();
    }
    });

var t2 = Task.Run(() => {
    for (int i = 0; i < 3; i++) {
        PrintHashPattern();
    }
});

Task.WaitAll(t1, t2);

void PrintStarPattern() {
    for (int i = 0; i < 3; i++) {
        for (int j = i; j < 3; j++) {
            Console.Write("*");
            Delay();
        }
        Console.WriteLine();
    }
    Console.WriteLine();
}

void PrintHashPattern() {
    for (int i = 0; i < 3; i++) {
        for (int j = i; j < 3; j++) {
            Console.Write("#");
            Delay();
        }
        Console.WriteLine();
    }
    Console.WriteLine();
}

void Delay() {
    for (int i = 0; i < 10000; i++) {
        for (int j = 0; j < 10000; j++) {
        }
    }
}

Output

  • The output shows the star and the hash pattens are interleaved. Making neither pattern clear

Solution

The above problem could be solved by mutual exclusion or locks. In C#, Mutexes (or locks) play a vital role. A thread can secure a lock on a resource to utilize it and then release it when done. Programmers in the system follow this practice of locking before accessing a resource and unlocking after accessing the resource.

The lock, established by .NET utilizing the operating system, ensures that once a task secures a lock, no other task can acquire it until the first one releases it. Any task attempting to lock a locked resource will move to a waiting state.

Code fix by lock

The below code solves the problem

  • consoleLock is an object

  • This object for the purposes of our program represents the resource "Console"

  • The task locks the object before accessing the console and unlocks the object after accessing the console

Object consoleLock = new object();

var t1 = Task.Run(() => { 
    for(int i = 0; i < 3; i++) {
        lock(consoleLock) {
            PrintStarPattern();
        }
    }
});

var t2 = Task.Run(() => {
    for (int i = 0; i < 3; i++) {
        lock(consoleLock) {
            PrintHashPattern();
        }
    }
});

Task.WaitAll(t1, t2);


void PrintStarPattern() {
    for (int i = 0; i < 3; i++) {
        for (int j = i; j < 3; j++) {
            Console.Write("*");
            Delay();
        }
        Console.WriteLine();
    }
    Console.WriteLine();
}


void PrintHashPattern(){
    for (int i = 0; i < 3; i++) {
        for (int j = i; j < 3; j++) {
            Console.Write("#");
            Delay();
        }
        Console.WriteLine();
    }
    Console.WriteLine();
}

void Delay() {
    for (int i = 0; i < 10000; i++) {
        for (int j = 0; j < 10000; j++) {
        }
    }
}

Fixed output

  • The output after fixing the code shows start patterns and hash patterns clearly separated

Conclusion

In this blog we have understood the problem of accessing shared resources from different tasks/threads. And we have also seen how to solve them with lock in C#

0
Subscribe to my newsletter

Read articles from Nachiappan Kumarappan directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Nachiappan Kumarappan
Nachiappan Kumarappan