Ответ 1
Нет, не до тех пор, пока вы блокируете один и тот же объект. Рекурсивный код эффективно уже имеет блокировку, и поэтому может продолжаться беспрепятственно.
lock(object) {...}
является сокращением для использования класса Monitor. Как Марк указывает, Monitor
позволяет повторное включение, поэтому повторяющиеся попытки блокировка объекта , на котором текущий поток уже имеет блокировку, будет работать нормально.
Если вы начинаете блокировку на разных объектах, это когда вы должны быть осторожны. Обратите особое внимание на:
- Всегда приобретайте блокировки для определенного количества объектов в одной и той же последовательности.
- Всегда отключайте блокировки в последовательности reverse, чтобы получить их.
Если вы нарушаете одно из этих правил, вы в значительной степени гарантируете, что в какой-то момент возникнут проблемы с блокировкой.
Вот одна хорошая веб-страница, описывающая синхронизацию потоков в .NET: http://dotnetdebug.net/2005/07/20/monitor-class-avoiding-deadlocks/
Кроме того, блокируйте как можно меньше объектов за раз. По возможности используйте крупнозернистые замки. Идея состоит в том, что если вы можете написать свой код так, чтобы существовал граф объектов, и вы можете получить блокировки в корне этого графа объектов, тогда сделайте это. Это означает, что у вас есть одна блокировка на этом корневом объекте, и поэтому вам не нужно так беспокоиться о последовательности, в которой вы приобретаете/освобождаете блокировки.
(Еще одно замечание: ваш пример не является технически рекурсивным. Для того, чтобы он был рекурсивным, Bar()
должен был бы вызывать себя, как правило, как часть итерации.)