Почему вложенные блокировки не вызывают тупик?

Возможный дубликат:
Заблокированные блокировки на С#

Почему этот код не вызывает тупик?

   private static readonly object a = new object();

...

   lock(a)
   {
      lock(a)
      {
         ....
      }
   }

Ответ 1

Если поток уже содержит блокировку, то он может "принять эту блокировку" снова без проблем.


Что касается того, почему это (и почему это хорошая идея), рассмотрим следующую ситуацию, когда у нас есть определенный порядок блокировки в другом месте программы a → b:

void f()
{
    lock(a)
    { /* do stuff inside a */ }
}

void doStuff()
{
    lock(b)
    {
        //do stuff inside b, that involves leaving b in an inconsistent state
        f();
        //do more stuff inside b so that its consistent again
    }
}

Упс, мы просто нарушили порядок блокировки и имели потенциальный тупик в наших руках.

Нам действительно нужно иметь возможность сделать следующее:

function doStuff()
{
    lock(a)
    lock(b)
    {
        //do stuff inside b, that involves leaving b in an inconsistent state
        f();
        //do more stuff inside b so that its consistent again
    }
}

Итак, наше упорядочение блокировки поддерживается без самозатухающего при вызове f().

Ответ 2

Ключевое слово lock использует блокировку повторного входа, то есть текущий поток уже имеет блокировку, поэтому он не пытается ее восстановить.

Тупик возникает, если

Тема 1 получает блокировку A
Тема 2 получает блокировку B
Thread 1 пытается получить блокировку B (ждет выполнения Thread 2) Thread 2 пытается получить блокировку A (ждет завершения Thread 1)

Оба потока теперь ждут друг друга и, таким образом, блокируются.

Ответ 3

Из раздела 8.12 спецификации языка С#:

В то время как блокировка взаимного исключения сохраняется, выполнение кода в одном и том же исполнении поток также может получать и освобождать замок. Однако код, выполняемый в других потоки заблокированы от получения блокировки до тех пор, пока блокировка не будет отпущена.

Очевидно, что внутренняя область lock находится в том же потоке, что и внешний.