如果实例是可公开访问的,则使用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);
}
}
}
锁定一个可公开访问的对象并非不可能,这只是一个非常糟糕的主意,因为它使理解对象的同步更加困难。一般做法是永远不要锁定在当前类型作用域之外可访问的对象,因为这样可以很容易地跟踪所有可能获得锁的位置,从而更容易诊断同步的潜在问题,并在查看代码时了解正在同步的确切内容。
当你在一个公开的对象上同步时,它会工作,这只是意味着如果你遇到一个问题,你有一个巨大的空间来查看,试图找出有问题的交互是什么。当许多不同地方的不同代码都在与被锁定的对象交互时,它也更容易导致死锁。
来自Parallel.Invoke
的文档:
执行每个提供的操作,可能是并行执行。
下面是发生的事情:
- 你的第一个动作在与主函数调用, 相同的线程中运行
- c#中的锁是可重入的,所以
Method1
可以重新获取锁。
下面的代码打印线程id-s来证明Main
和Method1
在同一个线程中运行。
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显示Method1
和Main
运行在同一个线程中