【问题标题】:How to use Multiple Variables for a lock Scope in C#如何在 C# 中使用多个变量作为锁定范围
【发布时间】:2010-05-20 13:17:03
【问题描述】:

我有一种情况,只有在两个 locker 对象空闲时才应该执行一段代码。

我希望会有类似的东西:

lock(a,b)
{
    // this scope is in critical region
} 

但是,似乎没有这样的事情。那么这是否意味着这样做的唯一方法是:

lock(a)
{
    lock(b)
    {
        // this scope is in critical region
    }
}

这甚至会按预期工作吗?虽然代码可以编译,但我不确定它是否能达到我的预期。

【问题讨论】:

  • 这不会导致锁定问题吗?假设一个对象锁定 a,另一个锁定 b,现在您将遇到死锁,其中 object1 阻塞 a 等待 b,而 object2 阻塞 b 等待 a。我对锁不太熟悉,但这似乎很糟糕。
  • 这就是锁定顺序很重要的原因,正如迄今为止所有答案所提到的那样。有时您需要拥有多个锁,在这些情况下,要使用的标准模式之一是强制(至少通过约定)对锁进行排序。例如,您会说,任何时候您想要获得 b 上的锁,您必须首先获得 a 上的锁。导致更多争用,但防止死锁。尽可能避免这种事情总是更好,但有时这是必要的。
  • @Tester101:是的,我知道如果处理不当会导致死锁。

标签: c# multithreading locking critical-section


【解决方案1】:
lock(a) lock(b) { // this scope is in critical region }

这可能会阻塞,直到线程可以获取a 的锁。然后,在获得该锁后,它将阻塞,直到线程可以获得b 的锁。所以这按预期工作。

但是,您必须小心不要在其他地方这样做:

lock(b) lock(a) { // this scope is in critical region }

这可能会导致死锁情况,线程 1 已获取 a 的锁并等待获取 b 的锁,而线程 2 已获取 b 的锁并等待获取a 的锁。

【讨论】:

    【解决方案2】:

    请求锁定两者应该可以正常工作。 lock(a) 将阻塞直到 a 空闲。一旦你拥有了那个锁,lock(b) 就会阻塞,直到你拥有b。之后你就有了。

    您需要非常小心的一件事是订单。如果您打算这样做,请确保您始终在获得b 的锁定之前获得a 的锁定。否则你很容易陷入僵局。

    【讨论】:

      【解决方案3】:

      我希望它会发生,但在某些情况下它可能会导致死锁情况。

      通常,代码会尝试锁定a,如果成功则继续锁定b。这意味着它只有在同时锁定ab 时才会执行代码。这就是你想要的。

      但是,如果其他代码已经锁定了b,那么此代码将不会执行您所期望的操作。您还需要确保在需要锁定ab 的任何地方都尝试以相同的顺序获得锁定。如果你先得到b,然后得到a,你会导致死锁。

      【讨论】:

      • 实际上,如果其他东西在 b 上锁定,它不会失败 - 它会等到它被释放。
      • @TomTom:如果另一个线程只是尝试访问其中一个锁,那么我们不会有任何问题,但是如果它尝试同时锁定 a 和 b 并且以相反的顺序,则存在陷入僵局的好机会。 @ChrisF:它们在您的编辑中是必需的,还是您这样做只是为了让代码看起来更干净?
      • @Gunner - 只是试图使代码看起来更清晰并阐明锁的范围。希望没关系。
      • @ChrisF:嗯,没关系。我猜这些锁定作用域就像其他作用域上下文一样工作。例如,在很多嵌套for循环的情况下,我们通常不会为外层循环放置花括号。
      • @Gunner - 是的,最终只是编码风格的问题,但我觉得在没有工具帮助你的 IDE 之外查看代码时,它会增加一点清晰度。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-11-03
      • 2021-01-24
      • 1970-01-01
      • 2016-11-04
      • 2019-06-15
      • 2021-12-29
      相关资源
      最近更新 更多