死锁检测有序锁执行

时间:2013-03-17 10:16:54

标签: c# locking deadlock

我正在尝试实现一种机制,其中自动检查锁定顺序,并且在运行时无序地获取锁以避免死锁时抛出异常。参考实现如下。如果您发现此实施有任何问题,请通知我。非常感谢。

public class someResource
{
    private OrderedLock lock1 = new OrderedLock(1);
    private OrderedLock lock2 = new OrderedLock(2);

    public void lockInOrder()
    {
        lock1.AcquireWriteLock();
        lock2.AcquireWriteLock();
        // do something
        lock1.ReleaseWriteLock();
        lock2.ReleaseWriteLock();
    }

    public void lockOutOfOrder()
    {
        lock2.AcquireReadLock();
        lock1.AcquireReadLock(); // throws exception
        // read something
        lock2.ReleaseReadLock();
        lock1.ReleaseReadLock();
    }
}

public class OrderedLock : IDisposable
{
    private static readonly ConcurrentDictionary<int, object> createdLocks = new ConcurrentDictionary<int, object>();
    [ThreadStatic]
    private static ISet<int> acquiredLocks;

    private readonly ThreadLocal<int> refCount = new ThreadLocal<int>(false);
    private readonly ReaderWriterLockSlim locker = new ReaderWriterLockSlim(LockRecursionPolicy.SupportsRecursion);
    private readonly int id;

    /// <exception cref="InvalidOperationException">Duplicate identifier detected</exception>
    public OrderedLock(int id)
    {
        if (!createdLocks.TryAdd(id, null))
        {
            throw new InvalidOperationException("Duplicate identifier detected");
        }

        this.id = id;
        this.refCount.Value = 0;
    }

    public void AcquireReadLock()
    {
        this.CheckLockOrder();
        this.locker.EnterReadLock();
    }

    public void AcquireWriteLock()
    {
        this.CheckLockOrder();
        this.locker.EnterWriteLock();
    }

    public void ReleaseReadLock()
    {
        this.refCount.Value--;
        this.locker.ExitReadLock();
        if (this.refCount.Value == 0)
        {
            acquiredLocks.Remove(this.id);
        }
    }

    public void ReleaseWriteLock()
    {
        this.refCount.Value--;
        this.locker.ExitWriteLock();
        if (this.refCount.Value == 0)
        {
            acquiredLocks.Remove(this.id);
        }
    }

    public void Dispose()
    {
        while (this.locker.IsWriteLockHeld)
        {
            this.ReleaseWriteLock();
        }

        while (this.locker.IsReadLockHeld)
        {
            ReleaseReadLock();
        }

        this.locker.Dispose();
        this.refCount.Dispose();
        GC.SuppressFinalize(this);
    }

    /// <exception cref="InvalidOperationException">Invalid order of locking detected</exception>
    private void CheckLockOrder()
    {
        if (acquiredLocks == null)
        {
            acquiredLocks = new HashSet<int>();
        }

        if (!acquiredLocks.Contains(this.id))
        {
            if (acquiredLocks.Any() && acquiredLocks.Max() > this.id)
            {
                throw new InvalidOperationException("Invalid order of locking detected");
            }

            acquiredLocks.Add(this.id);
        }

        this.refCount.Value++;
    }
}

0 个答案:

没有答案