(вопрос исправлен): Пока все ответы включают в себя один поток, повторно входящий в область блокировки линейно, с помощью таких вещей, как рекурсия, где вы можете отследить шаги одного потока, дважды входящего в блокировку. Но возможно ли как-то, что один поток (возможно, из 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(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.");
}
}
}