Below is attempt to catch potential deadlocks at runtime in C#. Basically this class allows user to acquire locks in a pre-defined order only. I ran some basic tests and it appears to work. Please review and let me know if you find something wrong with implementation.
public class OrderedLock
{
[ThreadStatic]
static HashSet<int> mAcquiredLocks;
static ConcurrentDictionary<int, object> mCreatedLocks = new ConcurrentDictionary<int, object>();
private int mId;
private ThreadLocal<int> mRefCount = new ThreadLocal<int>(false);
private ReaderWriterLockSlim mLock;
public OrderedLock(int id)
{
if (!mCreatedLocks.TryAdd(id, null)) throw new ApplicationException("Duplicate identifier detected");
mId = id;
mRefCount.Value = 0;
mLock = new ReaderWriterLockSlim(LockRecursionPolicy.SupportsRecursion);
}
public void AcquireReadLock()
{
CheckLockOrder();
mLock.EnterReadLock();
}
public void AcquireWriteLock()
{
CheckLockOrder();
mLock.EnterWriteLock();
}
public void ReleaseReadLock()
{
mRefCount.Value -= 1;
mLock.ExitReadLock();
if (mRefCount.Value == 0) mAcquiredLocks.Remove(mId);
}
public void ReleaseWriteLock()
{
mRefCount.Value -= 1;
mLock.ExitWriteLock();
if (mRefCount.Value == 0) mAcquiredLocks.Remove(mId);
}
private void CheckLockOrder()
{
if (mAcquiredLocks == null) mAcquiredLocks = new HashSet<int>();
if (!mAcquiredLocks.Contains(mId))
{
if (mAcquiredLocks.Count > 0 && mAcquiredLocks.Max() > mId)
throw new ApplicationException("Invalid order of locking detected");
else
mAcquiredLocks.Add(mId);
}
mRefCount.Value += 1;
}
}