我有一个ManualResetEvent.有一次,我等着那个事件WaitOne.令我惊讶的是,我OnPaint在演出期间收到了一个活动WaitOne.这种情况经常发生.
堆栈跟踪如下所示:

我知道a WaitOne会阻塞当前线程,并且在事件触发之前不允许执行任何其他代码.
有人可以解释这里发生了什么吗
(问题修改):到目前为止,答案都包括一个线程重新进入锁定区域的线程,通过递归之类的东西,你可以跟踪单个线程进入锁定两次的步骤.但是有可能以某种方式,对于单个线程(可能来自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)
{ …Run Code Online (Sandbox Code Playgroud)