Блокировки повторного входа в С#

Будет ли следующий код приводить к взаимоблокировке с использованием С# на .NET?

 class MyClass
 {
    private object lockObj = new object();

    public void Foo()
    {
        lock(lockObj)
        { 
             Bar();
        }
    }

    public void Bar()
    {
        lock(lockObj)
        { 
          // Do something 
        }
    }       
 }

Ответ 1

Нет, не до тех пор, пока вы блокируете один и тот же объект. Рекурсивный код эффективно уже имеет блокировку, и поэтому может продолжаться беспрепятственно.

lock(object) {...} является сокращением для использования класса Monitor. Как Марк указывает, Monitor позволяет повторное включение, поэтому повторяющиеся попытки блокировка объекта , на котором текущий поток уже имеет блокировку, будет работать нормально.

Если вы начинаете блокировку на разных объектах, это когда вы должны быть осторожны. Обратите особое внимание на:

  • Всегда приобретайте блокировки для определенного количества объектов в одной и той же последовательности.
  • Всегда отключайте блокировки в последовательности reverse, чтобы получить их.

Если вы нарушаете одно из этих правил, вы в значительной степени гарантируете, что в какой-то момент возникнут проблемы с блокировкой.

Вот одна хорошая веб-страница, описывающая синхронизацию потоков в .NET: http://dotnetdebug.net/2005/07/20/monitor-class-avoiding-deadlocks/

Кроме того, блокируйте как можно меньше объектов за раз. По возможности используйте крупнозернистые замки. Идея состоит в том, что если вы можете написать свой код так, чтобы существовал граф объектов, и вы можете получить блокировки в корне этого графа объектов, тогда сделайте это. Это означает, что у вас есть одна блокировка на этом корневом объекте, и поэтому вам не нужно так беспокоиться о последовательности, в которой вы приобретаете/освобождаете блокировки.

(Еще одно замечание: ваш пример не является технически рекурсивным. Для того, чтобы он был рекурсивным, Bar() должен был бы вызывать себя, как правило, как часть итерации.)

Ответ 2

Ну, Monitor разрешает повторное включение, поэтому вы не можете затормозить себя... так что нет: он не должен делать

Ответ 3

Если поток уже удерживает блокировку, он не будет блокировать себя. Это обеспечивает инфраструктура .Net. Вам нужно только убедиться, что два потока не пытаются захватить одни и те же блокировки из последовательности по каким-либо кодам кода.

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

Ответ 4

Нет, этот код не будет иметь мертвых замков. Если вы действительно хотите создать тупиковый простейший, требуется как минимум 2 ресурса. Рассмотрим сценарий собаки и кости. 1. Собака имеет полный контроль над одной костью, поэтому любая другая собака должна ждать. 2. 2 собаки с двумя костями минимальны для создания тупика, когда они фиксируют свои кости соответственно и ищут других кости тоже.

.. так далее и т.д. n собак и м кости и вызывают более сложные тупики.