【问题标题】:Multiple object locking with variable object count具有可变对象计数的多对象锁定
【发布时间】:2022-01-07 08:29:13
【问题描述】:

我有一个我自己的类数组,大小为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 实例的引用数可能不同)

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

【问题讨论】:

  • “当我事先不知道我需要锁定多少个锁时” - 你确实知道 - 每个 A 正好 1 个你需要读取或修改.因此,您首先为您正在阅读参考列表的A 获取锁 - 然后您为参考A 获取相应的锁,进行修改,释放锁,一旦您完成了每次引用,都可以释放原来的锁
  • 您尝试做的事情很可能会导致您发现dining philosophers problem 很困难。
  • @TheodorZoulias 我的引用没有圆圈,这是在外部验证的,所以如果正确实施,应该不会出现死锁。
  • @MathiasR.Jessen 问题指定对象和所有引用的对象都需要在锁内一起使用。从字面上看,这就是问题陈述。为什么你认为他们可以访问每个对象或引用的对象而不需要锁定引用的对象?大量操作将需要在某个关键部分的持续时间内防止一个对象和许多相关对象从另一个线程更改。这是一件很常见的事情(通常在编译时就知道相关对象的数量)。
  • @MathiasR.Jessen 我更改了问题描述,我知道锁的数量,但它是可变的。问题是我如何使用lock () {} 结构来解决这种问题,因为使用Mutex 会导致错误时不释放它。

标签: c# multithreading locking mutex


【解决方案1】:

lock 只是 try/finally 中 Monitor.Enter 的简写,最后是 Monitor.Exit。您可以在循环中显式执行此操作。

提供关键部分的 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);
    }
}

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

【讨论】:

    猜你喜欢
    • 2015-02-26
    • 1970-01-01
    • 1970-01-01
    • 2013-09-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多