A semaphore is used to limit the number of threads that have access to a shared resource at the same time. In other words, a Semaphore allows you to implement non-exclusive locking and hence limit concurrency. You might think of a Semaphore as a non-exclusive form of a Mutex. In .NET, we use the System.Threading.Semaphore class to work with semaphores.
Create a mutex in C#
Let’s create a mutex object in .NET. Note that we use the WaitOne method on an instance of the Mutex class to lock a resource and the ReleaseMutex method to unlock it.
Mutex mutexObject = new Mutex(false, "Demo");
try
{
if (!mutexObject.WaitOne(TimeSpan.FromSeconds(10), false))
{
Console.WriteLine("Quitting for now as another instance is in execution...");
return;
}
}
finally
{
mutexObject.ReleaseMutex();
}
Let us now implement a real-life code example that uses a mutex to synchronize access to a shared resource. The following code listing demonstrates how you can use a Mutex object in C# to synchronize access to a critical section that writes data to a text file.
public static class FileLogger
{
private const string fileName = @"D:\Projects\MyLog.txt";
public static void WriteLog(string text)
{
using var mutex = new Mutex(initiallyOwned: false, "Global\\log");
try
{
mutex.WaitOne(1000);
File.AppendAllText(fileName, text);
}
catch (AbandonedMutexException)
{
mutex.ReleaseMutex();
mutex.WaitOne(1000);
File.AppendAllText(fileName, text);
}
finally
{
mutex.ReleaseMutex();
}
}
}
In the FileLogger class shown above, an attempt is made to acquire a mutex by blocking the current thread for 1000 milliseconds. If the mutex is acquired, the text passed to the AppendAllText method as a parameter is written to a text file. The finally block then releases the mutex by making a call to the ReleaseMutex method.