При каких условиях поток может входить в область блокировки (Monitor) более одного раза одновременно?

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

8
задан Edward Ned Harvey 21 December 2012 в 12:30
поделиться