Возможный дубликат:
Заблокированные блокировки на С#
Почему этот код не вызывает тупик?
private static readonly object a = new object();
...
lock(a)
{
lock(a)
{
....
}
}
Возможный дубликат:
Заблокированные блокировки на С#
Почему этот код не вызывает тупик?
private static readonly object a = new object();
...
lock(a)
{
lock(a)
{
....
}
}
Если поток уже содержит блокировку, то он может "принять эту блокировку" снова без проблем.
Что касается того, почему это (и почему это хорошая идея), рассмотрим следующую ситуацию, когда у нас есть определенный порядок блокировки в другом месте программы 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().
Ключевое слово lock использует блокировку повторного входа, то есть текущий поток уже имеет блокировку, поэтому он не пытается ее восстановить.
Тупик возникает, если
Тема 1 получает блокировку A
Тема 2 получает блокировку B
Thread 1 пытается получить блокировку B (ждет выполнения Thread 2)
Thread 2 пытается получить блокировку A (ждет завершения Thread 1)
Оба потока теперь ждут друг друга и, таким образом, блокируются.
Из раздела 8.12 спецификации языка С#:
В то время как блокировка взаимного исключения сохраняется, выполнение кода в одном и том же исполнении поток также может получать и освобождать замок. Однако код, выполняемый в других потоки заблокированы от получения блокировки до тех пор, пока блокировка не будет отпущена.
Очевидно, что внутренняя область lock находится в том же потоке, что и внешний.