Tuesday, 26 September 2017

Mutex vs Semaphore vs Monitor vs SemaphoreSlim using example

Introduction
Hello Friends..! In this article document we will understand how to work on multi-thread environment using mutex, semaphore, monitor and semaphoreslim. Before reading this article I strongly suggest you to read our previous c-sharp articles on threading and types of threading and thread pooling. For more information threading click here and for thread pooling see here.
Before we talk about mutex, semaphore, monitor and semaphoreslim and their differences let's understand what is thread safety.

What is Thread Safe in C#

If an object behaves abnormally in a multi-threaded environment then that thread is not thread safe. For example : Let's say if we run a divide function with random numbers in a multi-threaded environment since it is running in a multi-threaded environment there could be possibility that two threads are executing divide calculation same time using random numbers can create system.dividebyzeroexception error. If these types of errors occurs in a multi-thread environment that means thread is not thread safe. So it means we should take some precaution while working in a multi-threaded environment atleast those lines of code where we feel code can behave abnormally. The precaution or thread safety can be achieved using proper thread synchronization techniques. Currently available thread synchronization techniques in c-sharp are Lock/Monitor, Mutex, Semaphore and SemaphoreSlim.

Lock vs Monitor

Lock keyword is very important in multithreading. It ensures thread safety and in a multithreading environment it ensures only one thread to be executed in given moment of time. In simple words whatever code is enclosed in lock scope only one thread can enter in that lock scope and other threads have to wait till entered thread completes its work/ executes its work.

C# Lock Example

Here in this example we will first execute a simple console application divide function in a multi-thread environment without thread safety to check the output exception error. We will take up the same example as we explained in the thread safety section.
01using System;
02using System.Collections.Generic;
03using System.Linq;
04using System.Text;
05using System.Threading;
06 
07namespace ConsoleApplication1
08{
09    class Program
10    {
11        static int num1 = 0;
12        static int num2 = 0;
13        static Random random = new Random();
14        static void Main(string[] args)
15        {
16 
17            Thread obj = new Thread(Divide);
18            obj.Start();
19 
20            Divide();
21        }
22 
23        static void Divide()
24        {
25             
26            for (int i = 0; i <= 5000; i++)
27            {
28 
29                try
30                {
31                    //Choosing random numbers between 1 to 5
32                    num1 = random.Next(1, 5);
33                    num2 = random.Next(1, 5);
34 
35 
36                    //Dividing
37                    double ans = num1 / num2;
38 
39 
40                    //Reset Variables
41                    num1 = 0;
42                    num2 = 0;
43                }
44                catch (Exception ex)
45                {
46                    Console.WriteLine(ex.ToString());
47                }
48            }
49        }
50    }
51}
Above code example is a simple console application example which executes Divide function in a multi-threaded way. Divide method loops 5000 times and takes two random numbers between 1 to 5 and divides themselves. When we ran this program we got the following error i.e. System.DividebyZeroException this because the method Divide is running in a multi-thread process i.e. static void main is the Main thread or Parent thread and inside that we have created one more thread object i.e. child thread.
So while running this program there could be possibility that while one thread is dividing other thread may be resetting the value to 0. Because of that it has created an DividebyZeroException error.
This is what we were talking about in the thread safety that is abnormal behave of an object in multithreading. To resolve this we can use any thread synchronization techniques but here as per situation best approach to use LOCK/Monitor.
To apply lock we need to use "LOCK" keyword as shown in below snippet of code.
01static readonly object _object = new object();
02 
03lock (_object)
04{
05         //Choosing random numbers between 1 to 5
06         num1 = random.Next(1, 5);
07         num2 = random.Next(1, 5);
08 
09         //Dividing
10         double ans = num1 / num2;
11 
12         //Reset Variables
13         num1 = 0;
14         num2 = 0;
15}

Monitor in c# example

Lock keyword is just a shot-form of Monitor. So usage of monitor class or lock is one and same. But here we will also show you same code example using Monitor class. Its pretty simple whatever code you want to protect at starting point say "Monitor.Enter" and at ending point say "Monitor.Exit" as shown in below code.
01Monitor.Enter(_object);
02 
03  //Choosing random numbers between 1 to 5
04         num1 = random.Next(1, 5);
05         num2 = random.Next(1, 5);
06 
07         //Dividing
08         double ans = num1 / num2;
09 
10         //Reset Variables
11         num1 = 0;
12         num2 = 0;
13 
14Monitor.Exit(_object);
So as you see friends LOCK and MONITOR ensures thread safety and prevent code from showing undesirable results.

Lock vs Mutex

Locks/Monitors ensures the thread safety which are in process that is threads which are generated by an application (Internal threads) it does not have any control over the threads which are coming from outside of an application. Locks/Monitors provides safety againts the threads generated by an application.
Mutex ensures the thread safety which are out process that is threads which coming from outside of an application (External threads). Mutex provides safety againts the external threads.
In a multiple instance of an application external threads are created so to ensure thread safety from an external threads we need to apply mutex. Let's see a simple example how to ensure thread safety from external threads.

Mutex example in C#

01class Program
02{
03        static Mutex m1 = new Mutex(true"Questpond");
04         
05        static void Main(string[] args)
06        {
07 
08            if (IsInstance() == true)
09            {
10                 
11                Console.WriteLine("New Instance created...");
12            }
13            else
14            {
15 
16                Console.WriteLine("Instance already acquired...");
17            }
18 
19            Console.ReadLine();
20        }
21 
22        static bool IsInstance()
23        {
24 
25            if (m1.WaitOne(5000,false) == false)
26            {
27                return false;
28            }
29            else
30            {
31                return true;
32            }
33           
34        }
35}
In the above code we have created a boolean function called "IsInstance" which checks whether any other instance is running or not and that we have achieved using "WaitOne" boolean function which blocks the current thread unit waithandle receives the signal. Here in our demonstration WaitOne waits for 5 secs to receive signal from waithandle if no signal received till 5 secs it will automatically return false. If its a new thread then automatically returns true.
To see the real time scenario follow these steps.
First build the complete source code
Second Go to application containing folder
Third EXE will be generated in the BIN folder so open BIN folder.
Fourth Click on that exe and create external threads.
Fifth Do not close that previous one exe.
Sixth By keeping that previous command line exe click on the same exe file to open another new command line exe.
Seventh Keep both command line exe and open more 2 or 3 times open new command line exe.
Output
First opened command line will display message as : New Instance created
All other opened command line will display messages as : Instance already acquired
Conclusion : It is been concluded that Mutex helps us to identify whether an application is acquired by an external thread or not.

Mutex vs Semaphore

Mutex helps us to identify whether an application is acquired by an external thread or not and It allows only one single thread to enter to execute a particular task. It means mutex allows only one single external thread to enter and execute its task and same ensuring thread safety.
Semaphore you can call its an advance version of mutex with additional features. Semaphore is also helps us to work with external threads and identifying whether an application is acquired by an external thread or not. But unlike mutex Semaphore allows one or more threads to enter to executes their task with thread safety. Best feature of semaphore that we can limit those number of threads to enter.

Semaphore example in c#

Let's see a simple example of using semaphore in c#.
01class Program
02{
03   
04    static Semaphore s1 = new Semaphore(2, 2, "SemaphoreQuestpond");
05     
06    static void Main(string[] args)
07    {
08 
09        if (IsInstance() == true)
10        {
11             
12            Console.WriteLine("New Instance created...");
13        }
14        else
15        {
16 
17            Console.WriteLine("Instance already acquired...");
18        }
19 
20        Console.ReadLine();
21    }
22 
23    static bool IsInstance()
24    {
25 
26        if (s1.WaitOne(5000, false) == false)
27        {
28            return false;
29        }
30        else
31        {
32            return true;
33        }
34       
35    }
36}
As you saw in our above code we have created a semaphore object "s1" limit of 2 threads with a name "SemaphoreQuestpond".
Now we will examine above example whether semaphore allows us to pass two external threads at a same time keeping thread safety.
First build the complete source code
Go to bin folder and click on exe file twice
Without closing both command file exe file click on exe file again
Output
First two opened command line will display message as : New Instance created
All other opened command line will display messages as : Instance already acquired
Conclusion : It is been concluded that semaphore helps us to identify whether an application is acquired by an external thread or not and at a same time allows to pass multiple threads (Limit) and keeps thread safety.

Monitor vs SemaphoreSlim

Lock is just short form of monitor. Monitor ensures thread safety with internal threads whatever code is enclosed between monitor enter and monitor exit only one thread can pass and executes its task.
SemaphoreSlim is an advance version of Monitor. SemaphoreSlim ensures the thread safety with internal threads but between scope of SemaphoreSlim it allows us to pass one or more threads to pass and executes their task. SemaphoreSlim also provides you an advance limit where you can limit the number of threads for an execution.

No comments:

Post a Comment