我们有一个带有两个锁的代码,它们以不同的方法锁定同一对象。可以从不同的线程调用这两种方法。
这会陷入僵局吗?
我们应该在两种方法中使用相同的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/