1

有什么办法可以同时锁定 2 个不同的对象?我尝试使用lock(obj1, obj2){...},但出现此错误:

invalid expression term ','

更新: 正如许多用户告诉我尝试只使用一个锁,我很欣赏他们的建议,因为大多数时候它更可取,我只想展示一个我认为锁定 2 个对象更合理的案例. 考虑在不同线程之间共享 2 个队列的情况。你需要避免同时做Enqueue(item)Dequeue()。现在,在代码的特定部分,您希望从一个队列中获取一个元素并将其插入到第二个队列中。我知道可以这样做:

var itme;
lock(_lock1)
{
    item = q1.Dequeue();
    Monitor.Pulse(_lock1);
}
lock(_lock2)
{
    q2.Enqueue(item);
    Monitor.Pulse(_lock2);
}

但我认为锁定两者_lock1并且_lock2更具可读性和清洁性。

4

3 回答 3

4

我强烈建议您使用一个锁来避免死锁,并且您应该锁定一个单独的引用,而不是您要修改的对象。

class MyClass
{
    private readonly object _lock = new object();
    private readonly List<int> _myList = new List<int>();
    private int _index;

    public void MyOperation()
    {
        lock(_lock) 
        {
            _index++;
        }
    }

    public void MyOperation2()
    {
        lock(_lock) 
        {
            _myList[_index] = 27;
        }
    }
}
于 2013-09-26T11:49:42.087 回答
1

试试这个

lock(obj1)
{
   lock(obj2)
   {
        // here you have lock on obj1 and obj2
   }
}

lock 只接受一个参数。上面的示例将锁定第二个锁定范围内的两个项目。

也许它提供了问题的答案,但是:

在这里锁定并不意味着在锁定期间其他线程上的其他代码都不能访问或修改该对象。如果您锁定一个对象,任何其他线程都可以同时修改该对象。锁代码块允许您做的是使锁块内的代码成为单条目,即只有一个线程可以执行一次锁代码块,其他尝试执行相同代码块的线程将不得不等到所有者线程完成执行代码块。所以基本上你真的不需要在通常情况下锁定 2 个或更多对象。通过锁定您的目的是使代码块单一条目

简而言之,正如其他人提到的,这个解决方案是无用的,更好的是创建锁定所需的新对象。

于 2013-09-26T11:44:25.867 回答
1

使用两个(或更多)不同对象的语法lock如下。

lock (a) lock (b)
{
}

但是,通常不鼓励这种类型的使用。这有几个原因。

  • 声明锁的顺序必须在各处保持一致,否则可能会发生死锁。
  • 这几乎总是不必要的。
  • 这是一种代码气味。

在我看来,第一个原因确实是一种逃避。在开发过程中有无数种可能犯错误的方法。这只是众多之一。而且,事实上,纠正错误实际上很容易(相对于其他类型的错误)。只需确保始终以相同的顺序获取锁。另外,使用嵌套锁本身并没有什么危险(同样,只要正确完成)。嵌套锁总是被获取。只是它几乎总是通过调用其他类或通过不同的堆栈帧进行执行来隐式完成。

这里真正重要的是第二个和第三个原因。在同一段代码中获取两个锁是不必要的,因为一个锁几乎总是足够的。事实上,我认为我从来不需要在同一段代码中获取两个锁。至少没有明确表示。这是一种代码味道,因为这通常意味着您对问题的思考是错误的。这可能意味着代码很复杂,或者您正在使用奇怪的代码路径。将代码结构化为只需要一把锁可能会使代码更容易理解。

另外,我也想知道您是否对锁的工作原理感到困惑。如果您认为lock关键字中使用的对象实例受到同时访问的保护,那么您就错了。这不是lock关键字的工作方式。引用的对象lock旨在标记代码的关键部分,该部分保证不会与标记有相同对象引用的另一个(或相同)部分同时执行。

更新:

我看了你的例子,第一件事让我跳出来是这段代码可能不是线程安全的。我看不到所涉及的完整上下文。我所看到的是这个假设的类在内部使用了两个队列并且正在脉冲两个不同的锁。我可以做出一些推论,但它们可能是错误的。我很难想象你可能会在一个班级里做这样的事情。但是,话虽如此,您是否考虑过当执行此代码的线程在锁之间被抢占时会发生什么?这是您的班级进入半生不熟状态的机会(该项目不再在任何一个队列中)。当另一个线程试图使用这个类时会发生什么?它会优雅地处理物品悬而未决的情况吗?我必须看到更多代码才能进一步评论,

于 2013-09-26T14:58:02.620 回答