同一对象上的多个锁是否存在死锁情况?

Zeu*_*eus 2 c# multithreading locking task

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

这会进入僵局吗?我们应该在两种方法中使用相同的 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
  }   
}
Run Code Online (Sandbox Code Playgroud)

更新

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

Eri*_*ert 6

这会进入僵局吗?

不。

我们应该在两种方法中使用相同的 lock1 吗?

是的。在多个线程上访问特定对象时,您应该始终锁定同一个锁定对象。在您的特定情况下,您显示的代码完全错误且已损坏。每个列表应该有一个锁,并且每次访问列表时始终取出该锁。

如果您正在更新列表变量,那么同样的事情 - 您应该为列表变量设置一个锁,并且每次出于任何原因访问该变量时都需要在该锁下。

使用两个不同的锁的原因是移除发生在并行运行的各种任务中,但更新列表发生在每隔几秒运行一次的新线程中。

那没关系。所有更新,无论是删除还是其他,都必须在同一个锁下发生。

如果您处于频繁阅读者多而作者少的情况下,则有针对这些情况的专用锁。但这不是你的场景。

你没有问的一些问题:

什么导致死锁?

void Transfer(Account a1, Account a2, decimal amount)
{
  lock(a1)
  {
    lock(a2)
    {
      // do the transfer
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

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

锁定“嵌套”在同一线程上的同一对象是否会导致死锁?

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

我应该使用更好的技术吗?

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

你也应该阅读

关于 C# 中 lock 语句的困惑

  • @宙斯。您当前的情况是,您在红绿灯前等待绿灯亮十字路口**,因为你想开得快。你觉得这是个好主意吗?我觉得这不是个好主意。 (5认同)