2009 Advent Calendar December 19th

So far so good but there is one more thing I want the MutexLock to do. The Mutex object may throw an exception (AbandonedMutexException) when being waited for if the current owning thread terminates without releasing the mutex. I want to hide that fact in my MutexLock so I don't need to handle that exception everywhere in my code:

1: public class Given_an_abandoned_lock : IDisposable
2: {
3: private MutexLock _lock = new MutexLock();
4: private EventWaitHandle _threadStarted = new EventWaitHandle(false, EventResetMode.ManualReset);
5: private EventWaitHandle _threadStop = new EventWaitHandle(false, EventResetMode.ManualReset);
6: private Thread _thread;
8: public Given_an_abandoned_lock()
9: {
10: _thread = new Thread(() =>
11: {
12: _lock.Lock();
13: _threadStarted.Set();
14: _threadStop.WaitOne();
15: });
16: _thread.Start();
17: }
19: public void Dispose()
20: {
21: if (_thread != null)
22: {
23: _thread.Abort();
24: }
25: }
27: [Fact(Timeout=1000)]
28: void It_should_be_possible_to_take_lock_when_thread_dies()
29: {
30: _threadStarted.WaitOne();
31: _threadStop.Set();
32: Assert.DoesNotThrow(() => { _lock.Lock(); });
33: }
34: }

And that test leads to the following implementation:

1: public class MutexLock : Lock
2: {
3: private readonly Mutex _lock = new Mutex();
5: public void Lock()
6: {
7: try
8: {
9: _lock.WaitOne();
10: }
11: catch (AbandonedMutexException) {}
12: }
14: public void Unlock()
15: {
16: _lock.ReleaseMutex();
17: }
18: }

Comments (2)

  1. Matthew says:

    Why would you ever want to silently allow another thread to terminate when a lock is held?  The underlying data is now in an unknown state; isn’t it appropriate to die?

  2. @Matthew: I think you’re right that a thread terminating without releasing the lock is one of twobad things. Either the thread terminated early because of some other problem or the programmer did somethign wrong. Programmer errors can be handled by an assert in the code but are not really a big problem for other threads from the Mutex’ perspective since you just forgot to release it. So I think it is OK to "ignore" it in this case.

    In the case a of a crashing thread things may definitly be in a weird state. Not only from a mutex point of view. So do I think it is better to terminate the application or try to continue? I think the answer is "it depends". In some cases, for example a high availability service I would try to survive as long as possible and always be defensive in the code, never assuming anything. For a simple user application – yeah I would consider terminating the program – if it is an acceptable user experience.

    Either way the important thing is to add one (or more tests) to document the desired behavior.

Skip to main content