我们有一个带有两个锁的代码,它们以不同的方法锁定同一对象。可以从不同的线程调用这两种方法。

这会陷入僵局吗?
我们应该在两种方法中使用相同的lock1吗?

使用两个不同锁的原因是,删除是从并行运行的各种任务中发生的,而更新列表是从每隔几秒钟运行的新线程发生的。

private static Object Lock1 = new Object();
private static Object Lock2 = new Object();
private static List<string> list = new List<string>();

public void Method1()
{
  lock(Lock1)
  {
   //update list
  }
}

public void Method2()
{
  lock(Lock2)
  {
    //remove from list
  }
}

更新

感谢您的健康讨论,我更新了代码,以使用.net提供的线程安全集合BlockingCollection。我继续使用lock1,因为我需要控制列表可以包含多少个对象。我现在已经删除了lock2,因为它不需要线程安全列表。

最佳答案



不。



是的。访问多个线程上的特定对象时,应始终锁定同一锁定对象。在您的特定情况下,您显示的代码完全错误且已损坏。您应该为每个列表设置一个锁,并且每次访问该列表时都必须保持该锁的状态。

如果要更新列表变量,则需要做同样的事情-您应该为列表变量设置一个锁,并且每次每次访问时,由于任何原因需要处于该锁之下,您都必须访问变量



没关系所有更新(无论是删除还是其他更新)都必须在相同的锁下进行。

如果您遇到的读者很多而作者很少的情况,则有针对这些情况的专用锁。但这不是您的情况。

您没有提出的一些问题:


void Transfer(Account a1, Account a2, decimal amount)
{
  lock(a1)
  {
    lock(a2)
    {
      // do the transfer
    }
  }
}

假设线程X调用Transfer(savings, checking, 100)并达到锁定savings的程度。然后我们切换到线程Y,它调用Transfer(checking, savings, 50)。我们锁定checking,然后尝试锁定savings,但是不能锁定,因为X拥有它。然后,我们切换回X,它尝试锁定checking,但是不能锁定,因为Y拥有它。然后,我们永远等待。那是一个僵局。



否。答案是错误的。锁定您已经在线程上的锁会自动成功。



是的。多线程程序很难正确编写。如果需要,请使用高级对象,例如多线程集合或不可变集合,这些对象旨在有效地解决这些问题而无需显式锁定。

您还应该阅读

Confusion about the lock statement in C#

关于c# - 同一对象上的多个锁是否存在死锁情况?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/46285808/

10-11 22:47
查看更多