我想看看如果你改变一个被 Monitor.Enter() 锁定的对象的引用会发生什么。正如预期的那样,抛出了 SynchronizationLockException。但是我很惊讶地看到在抛出异常之前有几个线程通过了监视器。
这是下面的代码正在做的事情。
- 创建并启动 100 个线程
- 让所有线程等待,直到设置 ManualResetEvent。
- 设置 ManualResetEvent - 有点像在 Indy 比赛中挥舞绿旗。
- 在 x 上设置排他锁 (Monitor.Enter(x))
- 更改 x 的参考。
在这一点上,我预计会引发某种异常,但直到 Monitor.Exit(x) 才会发生这种情况。真正奇怪的是,在引发异常之前,似乎有 10 - 20 个线程能够通过锁。这是怎么发生的?似乎不应该。当然,更改独占锁定对象的引用是不行的。我永远不会在真正的代码中这样做,但我仍然惊讶地看到其他线程通过监视器。你的意见?
using System;
using System.Threading;
namespace ThreadingPlayground
{
class Program
{
private int _value;
object x = new object();
ManualResetEvent _event = new ManualResetEvent(false);
static void Main()
{
Program p = new Program();
p.StartThreads();
Console.ReadLine();
}
private void StartThreads()
{
for(int i = 0;i<100;i++)
{
Thread t = new Thread(IncrementValue);
t.Start();
}
_event.Set();
}
private void IncrementValue()
{
WaitHandle.WaitAll(new WaitHandle[] {_event});
Monitor.Enter(x);
// Change the reference of the exclusively locked object. This
// allows other threads to enter, should this be possible?
x = Thread.CurrentThread.ManagedThreadId.ToString();
Console.WriteLine(++_value);
// throws a SynchronizationLockException
// but not until 10 - 20 more lines are written
Monitor.Exit(x);
}
}
}