Multithreading – Lock and Mutex

By | 01/06/2022

In this post, we will see how to use Lock and Mutex for obtaining a lock in a thread.

We start creating a Console application where, we will add a class called Methods:

[METHODS.CS]

using System;
using System.Threading;

namespace LockAbortThread
{
    public class Methods
    {
        public void RunMethods()
        {
            Thread firstThread = new Thread(MethodOne);
            Thread secondThread = new Thread(MethodOne);

            firstThread.Start();
            secondThread.Start();
        }


        private void MethodOne()
        {
            for (int i = 1; i < 6; i++)
            {
                Console.WriteLine($"Output: {i}    ---- ThreadId:{Thread.CurrentThread.ManagedThreadId}");
                Thread.Sleep(1000);
            }
        }
    }
}



Then, we modify the Program file in order to run RunMethods():
[PROGRAM.CS]

using System;

namespace LockAbortThread
{
    internal class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Start threads");
            Methods objMethods = new Methods();

            objMethods.RunMethods();
        }
    }
}



Now, if we run the application, this will be the result:


In this example, if we would like to run the two Threads in sequence, we could either use the method Join() (we have seen it in the post: Multithreading – Joining Threads) or, we could use the keyword LOCK.
With the keyword LOCK, we are sure that no thread will enter a critical section of code while another thread is in that section:

[METHODS.CS]

using System;
using System.Threading;

namespace LockAbortThread
{
    public class Methods
    {
        public void RunMethods()
        {
            Thread firstThread = new Thread(MethodOne);
            Thread secondThread = new Thread(MethodOne);

            firstThread.Start();
            secondThread.Start();
        }


        private void MethodOne()
        {
            lock(this)
            {
                for (int i = 1; i < 6; i++)
                {
                    Console.WriteLine($"Output: {i}    ---- ThreadId:{Thread.CurrentThread.ManagedThreadId}");
                    Thread.Sleep(1000);
                }
            }
        }
    }
}



Now, if we run the application, this will be the result:


LOCK it is used in simple situations because, it doesn’t have any parameters or methods that could help us to resolve for example a deadlock.
A deadlock is a situation where, two or more threads, are frozen in their execution because they are waiting for each other to finish.
In order to avoid a deadlock, we can use Mutex that is synchronization primitive that can also be used for interprocess synchronization.
It works like a Lock because, it acquires an exclusive lock on a shared resource from concurrent access but, it works across multiple processes.
For other information: Microsoft web site.

We can use Mutex is this simple way:

using System;
using System.Threading;

namespace LockAbortThread
{
    public class Methods
    {
        private static Mutex mutex = new Mutex();
        public void RunMethods()
        {
            Thread firstThread = new Thread(MethodOne);
            Thread secondThread = new Thread(MethodOne);

            firstThread.Start();
            secondThread.Start();
        }


        private void MethodOne()
        {
            mutex.WaitOne();
            for (int i = 1; i < 6; i++)
            {
                Console.WriteLine($"Output: {i}    ---- ThreadId:{Thread.CurrentThread.ManagedThreadId}");
                Thread.Sleep(1000);
            }
            mutex.ReleaseMutex();
        }
    }
}



If we run the application, this will be the result:

We can see that it works fine but, in reality, this implementation has the same problem with the deadlock like a LOCK.
In order to avoid a deadlock with Mutex, we can insert a timeout.
If Mutex doesn’t run after a specific number of seconds, the system will stop the execution of the application, avoiding in this way a deadlock:

using System;
using System.Threading;

namespace LockAbortThread
{
    public class Methods
    {
        private static Mutex mutex = new Mutex();
        public void RunMethods()
        {
            Thread firstThread = new Thread(MethodOne);
            Thread secondThread = new Thread(MethodOne);

            firstThread.Start();
            secondThread.Start();
        }


        private void MethodOne()
        {
            // the value is in Milliseconds
            // if after 6 seconds, the thread cannot run, it will stop to run
            if(mutex.WaitOne(6000))
            {
                for (int i = 1; i < 6; i++)
                {
                    Console.WriteLine($"Output: {i}    ---- ThreadId:{Thread.CurrentThread.ManagedThreadId}");
                    Thread.Sleep(1000);
                }
                mutex.ReleaseMutex();
            }
            else
            {
                // System is busy and application cannot run the Thread
                Console.WriteLine("Application can run a Thread. The system is busy.");
            }
        }
    }
}



If we run the application, this will be the result:

But now, if we set the Timeout to 5 seconds, we will see that the application will stop after the first thread because it tooks more of 5 seconds to complete the first method:

private void MethodOne()
 {
       // the value is in Milliseconds
       // if after 5 seconds, the thread cannot run, it will stop to run
       if(mutex.WaitOne(5000))
       {
            for (int i = 1; i < 6; i++)
            {
                .
                ..
                ...
}



If we run the application, this will be the result:



Leave a Reply

Your email address will not be published.