C# Threading: Mutual exclusion (via Mutex Class)
August 3, 2010 by
Christoff Truter
C#
Threading
Observe the following faulty snippet (don't use):
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);
}
}
}
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.
We need some kind of synchronization mechanism to ensure that our threads
access shared resources when appropriate.
In the .NET framework one of the solutions is to use the Mutex ("Mutual exclusion") class to aid us with this issue.
In the following snippet the issue gets resolved by adding a Mutex instance to it:
static Mutex mutex = new Mutex();
static void WriteToFile()
{
mutex.WaitOne();
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);
}
Console.WriteLine("{0} releasing resource", ThreadName);
mutex.ReleaseMutex();
}
The first thread that reaches the critical section (writing of the file) takes ownership
of the mutex - the other threads simply wait for the mutex to be released by the thread
that owns it - each taking ownership once its released etc etc etc.
Basically its like making a queue behind a resource and only one thread is allowed to use the resource at a time.
We do however get a more lightweight class in the .NET framework that provides mutual-exclusion as well, namely the
Monitor class (or lock statement).
What makes the Mutex class different (and more powerful) can be observed in the following snippet:
using System;
using System.Threading;
class Program
{
static void Main(string[] args)
{
bool createdNew;
using (Mutex mutex = new Mutex(true, "App", out createdNew))
{
if (!createdNew)
{
Console.WriteLine("Application already open");
return;
}
Console.WriteLine("Press any key to continue...");
Console.ReadKey();
}
}
}
Mutexes can be accessed system wide and across app domains & terminals, in the preceding snippet we prevent an user of opening multiple
instances of our process.
There are two types of Mutexes, local(unnamed) - which is only available within its parent process (like the first snippet) and global(named) which is
available system wide (like in the last snippet).
Additionally we can set the visibility of a global(named) mutex with regards to Terminal Services. If our named mutex starts with "Global\", it
becomes visible to all terminal sessions, if it starts with "Local\" its only available to the terminal session that created it.
Additional reading:
C# Threading: Mutual exclusion (via Monitor Class)
http://msdn.microsoft.com/en-us/library/system.threading.mutex.aspx
Mutex abandoned prematurely January 14, 2011 by Christoff Truter
An abandoned mutex indicates a serious programming error. http://msdn.microsoft.com/en-us/library/system.threading.abandonedmutexexception.aspx Basically - you're required to explicitly release your mutex before the process that owns the mutex terminates - else it will result in an abandoned mutex exception. Which indicates that the process that owned the mutex might have prematurely ended - crashed etc. (or it was never released in code - but hey .net can't know for sure - so it assumes that something probably went wrong)