(问题已修改):到目前为止,答案都包括单个线程通过递归等方式线性重新进入锁定区域,您可以在其中跟踪单个线程两次进入锁定的步骤。但是是否有可能以某种方式生成单个线程(可能来自 ThreadPool,可能是由于计时器事件或异步事件或线程进入睡眠状态并分别在其他一些代码块中被唤醒/重用)以某种方式产生两个彼此独立的不同地方,因此,当开发人员通过阅读自己的代码没想到会遇到锁重入问题时?
在 ThreadPool 类备注(点击这里)中,备注似乎建议休眠线程在不使用时应被重用,否则会因休眠而浪费。
但是在 Monitor.Enter 参考页面(单击此处)上,他们说“同一线程在不阻塞的情况下多次调用 Enter 是合法的。” 所以我想一定有一些我应该小心避免的事情。它是什么?一个线程怎么可能两次进入同一个锁定区域?
假设您有一些锁定区域需要很长时间。这可能是现实的,例如,如果您访问一些已被分页(或其他)的内存。锁定区域中的线程可能会进入睡眠状态或其他情况。同一个线程是否有资格运行更多代码,这些代码可能会意外进入同一个锁定区域?在我的测试中,以下内容不会让同一线程的多个实例运行到同一锁定区域。
那么如何产生问题呢?你究竟需要小心避免什么?
class myClass
{
private object myLockObject;
public myClass()
{
this.myLockObject = new object();
int[] myIntArray = new int[100]; // Just create a bunch of things so I may easily launch a bunch of Parallel things
Array.Clear(myIntArray, 0, myIntArray.Length); // Just create a bunch of things so I may easily launch a bunch of Parallel things
Parallel.ForEach<int>(myIntArray, i => MyParallelMethod());
}
private void MyParallelMethod()
{
lock (this.myLockObject)
{
Console.Error.WriteLine("ThreadId " + Thread.CurrentThread.ManagedThreadId.ToString() + " starting...");
Thread.Sleep(100);
Console.Error.WriteLine("ThreadId " + Thread.CurrentThread.ManagedThreadId.ToString() + " finished.");
}
}
}