如果实例是可公开访问的,则使用lock(this)

本文关键字:lock this 实例 访问 如果 | 更新日期: 2023-09-27 18:13:21

我正在寻找在锁中不使用"this"的答案,如果实例是可公开访问的。我尝试了下面的例子,我认为Method1将不会被调用,因为锁已经在实例的Main方法中获得。但是Method1被称为Method2无限期地等待。如有任何解释,敬请谅解。

class Program
{
    static void Main(string[] args)
    {
        Tracker tracker = new Tracker();
        lock (tracker)
        {
            Parallel.Invoke(() => tracker.Method1(),
                () => tracker.Method2());
        }
    }
}
class Tracker
{
    private int number = 6;
    public void Method1()
    {
        lock (this)
        {
            number *= 5;
            Console.WriteLine("Method1: " + number);
            number /= 4;
            Console.WriteLine("Method1: " + number);
        }
    }
    public void Method2()
    {
        lock (this)
        {
            number *= 3;
            Console.WriteLine("Method2: " + number);
            number /= 2;
            Console.WriteLine("Method2: " + number);
        }
    }
}

如果实例是可公开访问的,则使用lock(this)

锁定一个可公开访问的对象并非不可能,这只是一个非常糟糕的主意,因为它使理解对象的同步更加困难。一般做法是永远不要锁定在当前类型作用域之外可访问的对象,因为这样可以很容易地跟踪所有可能获得锁的位置,从而更容易诊断同步的潜在问题,并在查看代码时了解正在同步的确切内容。

当你在一个公开的对象上同步时,它会工作,这只是意味着如果你遇到一个问题,你有一个巨大的空间来查看,试图找出有问题的交互是什么。当许多不同地方的不同代码都在与被锁定的对象交互时,它也更容易导致死锁。

来自Parallel.Invoke的文档:

执行每个提供的操作,可能是并行执行

下面是发生的事情:

  • 你的第一个动作在与主函数调用
  • 相同的线程中运行
  • c#中的锁是可重入的,所以Method1可以重新获取锁。

下面的代码打印线程id-s来证明MainMethod1在同一个线程中运行。

class Program
{
    static void Main(string[] args)
    {
        Tracker tracker = new Tracker();
        Console.WriteLine("Main TID: " + Thread.CurrentThread.ManagedThreadId);
        lock (tracker)
        {
            Console.WriteLine("Main Acquired");
            Parallel.Invoke(() => tracker.Method1(),
                () => tracker.Method2());
        }
    }
}
class Tracker
{
    private int number = 6;
    public void Method1()
    {
        Console.WriteLine("Method1 TID: " + Thread.CurrentThread.ManagedThreadId);
        lock (this)
        {
            Console.WriteLine("Method1 Acquired");
        }
    }
    public void Method2()
    {
        Console.WriteLine("Method2 TID: " + Thread.CurrentThread.ManagedThreadId);
        lock (this)
        {
            Console.WriteLine("Method2 Acquired");
        }
    }
}

输出
Main TID: 1
Main Acquired
Method1 TID: 1
Method1 Acquired
Method2 TID: 3

然后挂起。Thread ID -s显示Method1Main运行在同一个线程中