tags:

views:

175

answers:

3

Hi Guys,

I was wondering which of the following was the suggested pattern when using Mutex (or Semaphores or ReadWriteLockSlims etc.).

Should the initial lock happen inside or outside of the try statement? Is it unimportant?

_mutex.WaitOne()
try
{
 // critical code
}
finally
{
  _mutex.ReleaseMutex();
}

or

try
{
  _mutex.WaitOne()
 // critical code
}
finally
{
  _mutex.ReleaseMutex();
}
+1  A: 

Maybe it is a different. Take a look into these posts from Eric:

In short: Just imagine there happens an exception between the mutex.WaitOne() and the try statement. You'll leave this chunk of code without calling the _mutex.ReleaseMutex().

So take your second piece of code to be sure everything works as expected.

Oliver
+2  A: 

The only way these could be different is if an exception occurred after WaitOne but before the try start in example 1 or after the try start but before WaitOne in example 2. In the first case, the mutex won't be released and in the second case a release might be attempted even though there is no pending wait. The exception would have to be something severe like ThreadAbortException for it to occur in either place. However, if the mutex is contained in a using block, neither would be a problem.

EDIT: after reading Eric's post on this topic that Oliver linked to, I think even with a using block, the situation is not perfect and that simply going with your second version as Oliver suggests is your best option.

Daniel Renshaw
How can a Mutex be used in a using block? If it exists only for the lifetime of the using block then no other thread can get access to it.
chillitom
Any object holding a reference to a mutex in a field should itself be disposable and propagate any dispose to the mutex. If the chain is complete, putting the top-level object (at the level of the lifetime you're after) in a dispose block will ensure the mutex is disposed. If the mutex lifetime == application lifetime then what's the problem? It'll be released when the application exists.
Daniel Renshaw
new Mutex() and _mutex.Dispose() are not the same as _mutex.WaitOne() and _mutex.ReleaseMutex().. the 'using' statement will handle the lifetime of the Mutex object but not the clean up of lock state after an exception the occurs during the lifetime of the mutex.
chillitom
I may not understand Mutex's well enough here but Dispose() calls Close() and doesn't Close() destroy the underlying unmanaged mutex entirely (unless it's a named system mutex)? It won't matter that it was never released, will it?
Daniel Renshaw
A: 

If you´r not using the mutex for cross-process synchronization.

See answer to this question C# - Locking issues with Mutex

Then this will be safer:

private static object _syncLock = new object();

public void RunCriticalCode()
{
    lock (_syncLock)
    {
        // critical code
    }
}
Jens Granlund
Thanks Jens that's a good point, seomthing to bear in mind. I guess here I'm was generalising for all locks though, I make quite extensive use of ReadWriteLockSlim in my code. Good answer though.
chillitom
@chillitom, ok, to answer you´r original question I will have to agree with Oliver´s answer.
Jens Granlund