在c#中锁定2个对象

时间:2013-09-26 11:43:10

标签: c# multithreading locking

有没有办法将两个不同的物体锁在一起? 我尝试使用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的锁定更具可读性和清晰度。

3 个答案:

答案 0 :(得分: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;
        }
    }
}

答案 1 :(得分:1)

试试这个

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

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

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

  

锁定此处并不意味着锁定的持续时间没有其他代码   在其他线程上可以访问或修改对象。如果你锁定一个对象   任何其他线程都可以同时修改对象。锁什么   代码块允许您做的是在锁定块内部生成代码   单个条目,即只有一个线程可以执行锁定代码块   尝试执行相同代码块的一次和其他线程将会   必须等到所有者线程完成执行代码   块。所以基本上你真的不需要锁定2个或更多的对象   通常的情况。通过锁定你的目的是使代码块单一   输入

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

答案 2 :(得分:1)

lock与两个(或更多)不同对象一起使用的语法如下:

lock (a) lock (b)
{
}

但是,通常不鼓励这种用法。这有几个原因。

  • 声明锁定的顺序必须在任何地方保持一致,否则可能会发生死锁。
  • 几乎总是没必要。
  • 这是一种代码味道。

在我看来,第一个原因真的是一个警察。有许多方法可以在开发过程中犯错误。这只是其中之一。而且,事实上,实际上很容易(相对于可以做出的其他类型的错误)。只需确保始终以相同的顺序获取锁。另外,使用嵌套锁没有任何固有的危险(再次,只要它正确完成)。嵌套锁是所有获取的时间。它只是通过调用其他类或执行通过不同的堆栈帧来隐式地完成。

这是第二个和第三个真正重要的原因。在同一代码段中获取两个锁是不必要的,因为一个锁几乎总是足够的。事实上,我认为我不需要在相同的代码段中获取两个锁;至少没有明确说明。这是一种代码味道,因为它通常意味着您正在考虑错误的问题。这可能意味着代码是错综复杂的,或者您使用的是奇怪的代码路径。构建代码以便只需要一次锁定就可以使代码更容易理解。

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

<强>更新

我看了一下你的例子,第一件事就是这个代码可能不是线程安全的。虽然我看不到完整的背景。我所看到的是,这个假设的类在内部使用两个队列并且正在发出两个不同的锁。我可以做一些推论,但它们可能是错的。我很难想象你可能会在一个班级里做这样的事情。但是,说到这一点,您是否考虑过在执行此代码的线程在锁之间被抢占时会发生什么?这是你的班级进入半生不熟的状态的机会(该项目不再在任何一个队列中)。当另一个线程试图使用这个类时会发生什么?是否会优雅地处理物品挂在空中的情况?我将不得不看到更多的代码进一步评论,但看到锁的安排允许一个半生不熟的状态开始是我的巨大红旗。