(質問の改訂):これまでのところ、すべての回答には、再帰などを通じて、ロック領域に直線的に再入る単一のスレッドが含まれています。再帰などでは、単一のスレッドがロックに2回入るステップを追跡できます。しかし、どういうわけか、単一のスレッド(おそらく、タイマーイベントまたは非同期イベントの結果として、またはスレッドがスリープ状態になり、コードの他のチャンクで個別に起動/再利用された結果として、ThreadPoolから)が何らかの形で生成される可能性はありますか? 2つの異なる場所が互いに独立しているため、開発者が自分のコードを読み取るだけでロックの再入力の問題が発生することを予期していなかった場合に、ロックの再入力の問題が発生しますか?
ThreadPoolクラスの備考(ここをクリック)では、備考は、スリープ状態のスレッドを使用していないとき、またはスリープ状態によって無駄になっているときに再利用する必要があることを示唆しているようです。
しかし、Monitor.Enterリファレンスページ(ここをクリック)では、「同じスレッドがブロックせずにEnterを複数回呼び出すことは合法です」と述べています。 だから私は避けるべき何かがあるに違いないと思います。それは何ですか?1つのスレッドが同じロック領域に2回入る可能性さえありますか?
残念ながら長い時間がかかるロック領域があるとします。これは、たとえば、ページアウトされたメモリ(またはその他)にアクセスする場合に現実的です。ロックされた領域のスレッドがスリープ状態になる可能性があります。同じスレッドがより多くのコードを実行できるようになり、誤って同じロック領域にステップインする可能性がありますか?以下は、私のテストでは、同じスレッドの複数のインスタンスを同じロック領域で実行することはできません。
では、どのようにして問題を引き起こすのでしょうか。避けるために注意する必要があるのは正確には何ですか?
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.");
}
}
}