4

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();
}
chillitom
  • 24,888
  • 17
  • 83
  • 118

3 Answers3

2

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
  • 33,729
  • 8
  • 75
  • 94
  • 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 Apr 30 '10 at 10:23
  • 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 Apr 30 '10 at 10:30
  • 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 Apr 30 '10 at 10:35
  • 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 Apr 30 '10 at 10:48
1

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
  • 43,366
  • 8
  • 94
  • 151
  • But don't you now call ReleaseMutex while another thread might be inside it allowing a second thread to enter? I.e. Thread A calls WaitOne and enters mutex -> Thread B calls WaitOne and blocks -> Thread C crashes and calls ReleaseMutex -> Thread B enters mutex together with Thread A. – Matthijs Wessels Nov 13 '14 at 11:51
0

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
    }
}
Community
  • 1
  • 1
Jens Granlund
  • 4,950
  • 1
  • 31
  • 31
  • 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 Apr 30 '10 at 10:49
  • @chillitom, ok, to answer you´r original question I will have to agree with Oliver´s answer. – Jens Granlund Apr 30 '10 at 11:01