潜在的死锁

本文关键字:死锁 | 更新日期: 2023-09-27 18:17:06

public class MyClass
{
  public void DoSomething()
  {
   Lock(this)
   {
        //Do Something.
   }
  }
}
public class AnotherClass
{
   MyClass myclass = new MyClass();
   Public void DoAnotherThing()
   {
     lock(myclass)
     {
        Myclass.DoSomething();
     }
   }
}

这会导致死锁吗?

根据我的理解和我读过的文章——会的。为什么?无论何时DoSomething()被调用,它都会尝试获得一个锁,并等待锁(myclass)被释放,从而导致死锁。

潜在的死锁

请确认我的理解(也需要一点解释),如果我错了请纠正。

我认为您所阅读的文章试图告诉您的是您不应该lock (this),因为其他一些代码也可能试图锁定相同的对象。只有当涉及两个或多个线程时才会发生这种情况。

下面是一些演示死锁问题的示例代码。试着运行它,看看结果。然后在lock (this)行做建议的编辑,然后再试一次。

发生死锁是因为类外部的一些代码锁定了类内部代码用来锁定的同一个类的实例——如果没有仔细的文档和可见性,这是很有可能发生的。

这个故事的寓意是,一般来说,你不应该锁定任何在类之外可见的东西(除非你仔细记录了如何使用该类的锁定),并且你应该永远不要lock (this)

using System;
using System.Threading.Tasks;
namespace Demo
{
    class MyClass
    {
        public void DoSomething()
        {
            Console.WriteLine("Attempting to enter the DoSomething lock.");
            lock (this) // Change to lock(_locker) to prevent the deadlock.
            {
                Console.WriteLine("In the DoSomething lock.");
            }
        }
        readonly object _locker = new object();
    }
    internal static class Program
    {
        static void Main(string[] args)
        {
            var myClass = new MyClass();
            lock (myClass)
            {
                var task = Task.Run(() => myClass.DoSomething());
                Console.WriteLine("Waiting for the task to complete.");
                if (!task.Wait(1000))
                    Console.WriteLine("ERROR: The task did not complete.");
                else
                    Console.WriteLine("Task completed.");
                Console.WriteLine("Press any key to continue...");
                Console.ReadKey();
            }
        }
    }
}

这不会造成死锁,因为只涉及一个线程。的确,当您的MyClass对象上的锁已经被持有时,就会请求该对象上的锁。但是c#锁是"递归的",这意味着一个线程可以在同一个对象上持有多个锁,结果就好像它只持有最外层的锁一样:内部锁立即成功,对象被锁定,直到最后一个锁被释放。(除非你被迫使用一种没有它的语言,否则你不会真正理解它有多有用。)

但我同意上面每个人的看法:lock(this)是坏兆头。