Crashing Through Deadlocks

Although concurrency management is somewhat represented in C# with the lock statement, there’s plenty more to be found in System.Threading namespace. Starting from Monitor class, which is what the lock statement is based on, to the ReaderWriterLock and the Mutex class. There’s even an Interlocked class, which provides very nice facilities for atomic operations.

In debugging deadlocks, I found myself using the Monitor.TryEnter method in order to determine the actual place of a deadlock. It basically operates as your standard Enter, except after a specified time span, it times out and returns false as the return value. Otherwise, when the thread is acquired, it returns true.

Inspired by a neat hack by Peter Golde, I created a simple wrapper — the ImpatientLock — for the TryEnter method, which allows adding the deadlock debugging statement with minimal modification to the existing code:

// lock(obj)
using(ImpatientLock.Try(obj))
{
   // .. do stuff
}

Except in the case of ImpatientLock, the exception is thrown, documenting the stack trace and thus pointing out location of the deadlock. Here’s the complete source code for the ImpatientLock, just in case you find it useful.

using System.Threading;

public class ImpatientLock
{
  public static IDisposable Try(object obj)
  {
    return new DisposableLock(obj, DisposableLock.DefaultTimeSpan);
  }

  public static IDisposable Try(object obj, TimeSpan timeSpan)
  {
    return new DisposableLock(obj, timeSpan);
  }

  private class DisposableLock : IDisposable
  {
    private static readonly TimeSpan DefaultTimeSpan = TimeSpan.FromMinutes(5);
    private readonly object Obj;
    public DisposableLock(object obj, TimeSpan timeSpan)
    {
      Obj = obj;
      if (!Monitor.TryEnter(obj, timeSpan))
      { 
          throw new ImpatientLockException();
      }
    }

    public void Dispose()
    {
      Monitor.Exit(Obj);
    }
  }

  private class ImpatientLockException : Exception
  {
    public ImpatientLockException()
      :base("Your time's up. I am quittin'!")
    {
    }
  }
}

In case you are battling deadlock issues, there are a couple of really good articles on the subject — most notably this one by Dr. GUI, and this one by unknown (to me) MS folks. There are also some pretty intriguing applications that attempt detection of potential deadlocks by analyzing the call tree of your code, although I found those too simplistic to detect anything realistically serious.

UPDATE: Ian Griffith has more information about this technique over at his blog, enhanced and updated with the help of Eric Gunnerson.

Leave a Reply

%d bloggers like this: