Подтвердить что ты не робот

Почему объект блокировки должен быть только для чтения?

При реализации блокировки я использовал для создания частного объекта внутри моего класса:

Если я хочу быть уверенным, что он заблокирован в потоке, который создал мой класс:

private object Locker = new object();

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

private static object Locker = new object();

Но здесь: Почему объект блокировки должен быть статическим?

и по ряду других вопросов каждый говорит, что объект должен быть readonly. Я не нашел причины - даже в MSDN или JavaDoc.

Как я часто использую такую ​​конструкцию, может кто-нибудь объяснить мне, почему я должен использовать readonly?

Спасибо!

4b9b3361

Ответ 1

Если я хочу быть уверенным, что он будет заблокирован для всех потоков внутри моего Применение:

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

все говорят, что объект должен быть "readonly", я не нашел причина

Ну, это не обязательно. Это просто лучшая практика, которая помогает избежать ошибок.

Рассмотрим этот код:

class MyClass
{
    private object myLock = new object();
    private int state;

    public void Method1()
    {
        lock (myLock)
        {
            state = // ...
        }
    }

    public void Method2()
    {
        myLock = new object();
        lock (myLock)
        {
            state = // ...
        }
    }
}

Здесь Thread1 может получить блокировку через Method1, но Thread2, который собирается выполнить Method2, будет игнорировать эту блокировку, поскольку объект блокировки был изменен = > состояние может быть повреждено.

Ответ 2

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

Ответ 3

Я предполагаю, что это означает, что "переменная, ссылающаяся на объект блокировки, должна быть прочитана только".

Вы блокируете объект блокировки, который ссылается на переменную, а не на переменную. То есть имея

private object Locker = new object();

вы блокируете этот новый объект(), а не в поле Locker. Затем, если вы замените значение поля ссылкой на другой объект, скажите

Locker = new object();

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

Ответ 4

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

Это был бы очень редкий случай. Но если у вас есть блокировка объекта и другой поток, ожидающий этого объекта, если блокирующий поток вызывает Monitor.Pulse, ожидание потока пробуждается и может блокировать объект. В течение этого периода времени между тем, как разбудить и взять замок, другой поток может изменить объект, на который делается ссылка в замке, и поэтому поток ожидания будет блокировать другой объект.