C# Threading: Mutual exclusion (via Monitor Class)



Observe the following faulty snippet from this post:

 
using System;
using System.Threading;
using System.IO;
 
class Program
{
    static void Main(string[] args)
    {
        for (int i = 0; i < 3; i++)
        {
            Thread thread = new Thread(new ThreadStart(ThreadMain));
            thread.Name = String.Concat("Thread - ", i);
            thread.Start();
        }
    }
 
    static void ThreadMain()
    {
        // Simulate Some work
        Thread.Sleep(500);
 
        // Access a shared resource / critical section
        WriteToFile();
    }
 
    static void WriteToFile()
    {
        String ThreadName = Thread.CurrentThread.Name;
        Console.WriteLine("{0} using resource", ThreadName);
 
        try
        {
            using (StreamWriter sw = new StreamWriter("1.txt", true))
            {
                sw.WriteLine(ThreadName);
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.Message);
        }
    }
}
 

Like earlier explained, what we've got here is three threads trying to write to a file, which fails horribly since we cant concurrently write to the same file.



Previously we used the Mutex class to resolve this issue, but we won't always need the power of the Mutex class (by which we can achieve a global lock on resources within our processes) - a lot (if not most) of the time the Monitor class will suffice.

Observe the monitor based solution:

 
static object locker = new object();
 
static void WriteToFile()
{
    String ThreadName = Thread.CurrentThread.Name;
    Console.WriteLine("{0} using resource", ThreadName);
 
    Monitor.Enter(locker);
    try
    {
        using (StreamWriter sw = new StreamWriter("1.txt", true))
        {
            sw.WriteLine(ThreadName);
        }
    }
    catch (Exception ex)
    {
        Console.WriteLine(ex.Message);
    }
    finally
    {
	Monitor.Exit(locker);
	Console.WriteLine("{0} releasing resource", ThreadName);
    }
}
 

Basically each thread will wait until the locker object gets released by the first thread that achieved a lock, before it attempts to write to our file.



Alternatively we can simply make use of the lock statement, which neatly wraps the Monitor.Enter - Monitor.Exit statements like this:

 
static object locker = new object();
 
static void WriteToFile()
{
    String ThreadName = Thread.CurrentThread.Name;
    Console.WriteLine("{0} using resource", ThreadName);
 
    lock (locker)
    {
        try
        {
            using (StreamWriter sw = new StreamWriter("1.txt", true))
            {
                sw.WriteLine(ThreadName);
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.Message);
        }
    }
}
 

We do however have more control (if needed) over our lock using the Monitor (instead of the lock statement), like visible in the next crude snippet:

 
if (Monitor.TryEnter(locker, 500))
{
    try
    {
        Console.WriteLine("Lock Achieved");
        Thread.Sleep(1000); // Simulate work
    }
    catch
    {
	throw;
    }
    finally
    {
        Monitor.Exit(locker);
    }
}
else
{
    Console.WriteLine("Lock Failed");
}
 

If a thread can't achieve a lock within our defined 500 milliseconds, we've got the ability to handle it - instead of just waiting forever (or whenever garbage collection eventually happens).

Note:
Generally fields that are read/written within multiple threads, should be read/written within a lock.

Vocabulary

Atomicity / Atomically
From the greek word "atomos" which means indivisible (early scientists prematurely named the atom after this word - which they used to consider to be the smallest building block of matter).

In context of thread locking and atomicity - If variables are only read/written within the same exclusive lock, it means that we isolate these variables to a specific thread, outside threads (concurrent processes) can't alter these variables - these variables are read/written atomically.

Additional reading:
C# Threading: Mutual exclusion (via Mutex Class)
http://msdn.microsoft.com/en-us/library/c5kehkcz(VS.71).aspx
http://msdn.microsoft.com/en-us/library/aa664735(VS.71).aspx

Note: Additional overloads added to .net 4.0
http://msdn.microsoft.com/en-us/library/system.threading.monitor.tryenter.aspx

Threading Guidelines:
http://msdn.microsoft.com/en-us/library/f857xew0%28VS.71%29.aspx







Post comment

Name *
Email
Title
Body *
Security Code
*
* Required fields

Related Posts

C# Threading: Semaphore


2010-09-18 22:51:47

C# Threading: COM Apartment Model


2010-09-13 12:04:25

C# Threading: BackgroundWorker


2010-03-20 22:51:51

Latest Posts

Be the best stalker you can be


2011-12-13 22:33:54

Syntactic sugar (C#): Enum


2011-08-04 16:50:18

Top 5 posts

Simple WYSIWYG Editor


Creating a WYSIWYG textbox for your website is actually quite simple.
2007-02-01 12:00:00

Moving items between listboxes in ASP.net/PHP example


Move items between two listboxes in ASP.net(C#, VB.NET) and PHP
2008-06-12 17:07:43

Cross Browser Issues: Firefox Word Wrapping


Firefox word wrapping issues
2008-06-09 09:51:21

Populate a TreeView Control C#


Populate a TreeView control in a windows application.
2009-08-27 16:01:03

C# YouTube : Google API


Post on how to integrate with YouTube using the Google Data API
2011-03-12 08:37:51