Monitor.Enter()によって排他的にロックされたオブジェクトの参照を変更するとどうなるかを確認したかったのです。予想どおり、SynchronizationLockExceptionがスローされました。しかし、例外がスローされる前に、いくつかのスレッドがモニターを通過するのを見て驚いた。
以下のコードが実行していることは次のとおりです。
- 100スレッドを作成して開始します
- ManualResetEventが設定されるまで、すべてのスレッドを待機させます。
- ManualResetEventを設定します-インディレースで緑の旗を振るようなものです。
- 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);
}
}
}