I don't understand why the .NET mutex does not either throw an AbandonedMutexException
in one of the waiting threads or release the mutex when Mutex.Dispose()
is called.
In particular, code like this will deadlock:
public static void testCall()
{
using (var mutex = new System.Threading.Mutex(false, "testname"))
{
mutex.WaitOne();
Console.WriteLine("second call");
}
}
public static void Main(string[] args)
{
var thread = new System.Threading.Thread(testCall);
using (var mutex = new System.Threading.Mutex(false, "testname"))
{
mutex.WaitOne();
Console.WriteLine("first call");
thread.Start();
System.Threading.Thread.Sleep(new TimeSpan(0, 0, 5));
Console.WriteLine("sleep done");
}
thread.Join();
}
Mind you, I understand the AbandonedMutexException
usually comes from the underlying WIN32 mutex and in native code would only be triggered in case the owning thread dies - I've been writing C/C++ code for a long time and am fully aware of the underlying design. I also know that the following code is an easy workaround:
using (var mutex = new System.Threading.Mutex(false, "testname"))
{
mutex.WaitOne();
try
{
Console.WriteLine("first call");
thread.Start();
System.Threading.Thread.Sleep(new TimeSpan(0, 0, 1));
Console.WriteLine("sleep done");
}
finally
{
mutex.ReleaseMutex();
}
}
What I don't understand is the rationale behind .NET mutexes not forcing a release when the object has been explicitly disposed of while holding the lock. Wouldn't that be more in-line with the rest of the .NET programming paradigm? If/when the developer explicitly destroys a locked mutex... it only makes sense to mark it as abandoned.
You probably don't want it to work the way that you suggest. Let's say you have this:
using (var m = new Mutex(....))
{
m.WaitOne();
// do some stuff here
// that ends up throwing an exception
}
The exception is thrown while your thread holds the mutex. If the mutex were released as part of the dispose, then some other thread could obtain the mutex and begin partying on the data that you were updating. Except that now the data is in an unknown (probably inconsistent or corrupt) state.
It's best, of course, to handle the exception and clean things up, but absent that I'd rather the mutex remain held (or abandoned if the thread dies) so that the next thread that tries to acquire the mutex knows that something bad happened.
In addition to the above, adding automatic release would require that the .NET wrapper keep track of which thread owns the mutex. And the Dispose
method would have to check that value to determine if it should call ReleaseMutex
. And it's just not possible to keep track of that. The .NET program could pass the mutex handle to some unmanaged code, which could acquire or release the mutex without the wrapper's knowledge.
So, the answer is twofold: First, it's not possible. Second, even if it were possible, you probably don't want that behavior.