具有可变对象计数的多对象锁定

Multiple object locking with variable object count

我有一个自己的数组 类,大小为 N。每个实例都可以引用数组中的其他实例,并在列表中保存索引列表。

class A
{
    public List<int> References { get; } = new List<int>();
}

A[] a_array = new A[N];

我想创建一个智能锁定系统 - 一个大小为 N 的数组,在每个索引中我为 a_array 中的每个实例持有一个锁。每当我更新或读取 a_array 中的实例时,我都需要锁定该实例及其所有引用。

object[] locks = new object[N];

foreach (var refer in a.References)
{
    // lock locks[refer];
}

当每个实例的锁数可变时,我如何在 C# 中锁定多个对象(每个 A 实例的引用数可能不同)

我知道我可以为此使用 Mutex,但我想确保在我的代码中抛出异常时释放 mutex。

lock 只是 shorthand for Monitor.Enter in a try/finally with a Monitor.Exit at the end。您可以在循环中明确地执行此操作。

提供关键部分的 lambda 意味着整个锁管理被紧密封装,使得忘记正确释放锁变得更难。

public static void LockAll(IEnumerable<object> lockObjects, Action action)
{
    List<object> enteredLocks = new List<object>();
    try
    {
        foreach (var lockObject in lockObjects)
        {
            Monitor.Enter(lockObject);
            enteredLocks.Add(lockObject);
        }

        action();
    }
    finally
    {
        foreach (var lockObject in enteredLocks)
            Monitor.Exit(lockObject);
    }
}
public static T LockAll<T>(IEnumerable<object> lockObjects, Func<T> func)
{
    List<object> enteredLocks = new List<object>();
    try
    {
        foreach (var lockObject in lockObjects)
        {
            Monitor.Enter(lockObject);
            enteredLocks.Add(lockObject);
        }

        return func();
    }
    finally
    {
        foreach (var lockObject in enteredLocks)
            Monitor.Exit(lockObject);
    }
}

对于锁定多个事物的任何情况,您需要确保始终以一致的顺序锁定项目以避免死锁。