Насколько глубока блокировка? - PullRequest
10 голосов
/ 11 августа 2009

У меня есть следующий код:

            locker = new object();
        lock (locker)
        {
            for (int i = 0; i < 3; i++)
                 ver_store[i] = atomic_Poll(power);                
        }

Я просто бродил, учитывая, что функция внутри блокировки обращается к некоторым глобальным ресурсам (включая открытый сокет), все ли глобальные ресурсы внутри объекта также заблокированы. (Я знаю, что любая другая функция, которая обращается к этим же переменным, должна реализовывать на них блокировку, чтобы механизм блокировки был действительным. Я просто еще не успел их заблокировать :))

Ответы [ 7 ]

11 голосов
/ 11 августа 2009

Оператор блокировки НЕ "блокирует код" или любой ресурс, который находится между фигурными скобками, как таковой.

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

Учитывая ваш пример кода

10  locker = new object();
11  lock (locker)
12  {
     ...
15  }

Когда поток X достигает строки 10, создается новый объект, а в строке 11 устанавливается блокировка для объекта. Поток X продолжает выполнять любой код внутри блока.

Теперь, пока поток X находится в середине нашего блока, поток Y достигает строки 10. И вот, создается новый объект, и, поскольку он создается потоком Y, в настоящее время блокировка этого объекта не осуществляется. Поэтому, когда поток Y достигает 11, он успешно получает блокировку объекта и продолжает выполнять блок одновременно с потоком X.

Это ситуация, которую замок должен был предотвратить. Так что делать? Сделать шкафчик общим объектом .

01  static object locker = new object();

    ...

11  lock (locker)
12  {
     ...
15  }

Теперь, когда поток X достигнет строки 11, он получит блокировку и начнет выполнение блока. Когда поток Y достигает строки 11, он пытается получить блокировку для того же объекта, что и поток X. Поскольку этот объект уже заблокирован, поток Y будет ждать, пока блокировка не будет снята. Таким образом предотвращая одновременное выполнение блока кода, тем самым защищая любые ресурсы, используемые этим кодом, для одновременного доступа.

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

4 голосов
/ 11 августа 2009

Блокировка влияет только на код в теле оператора блокировки. Объекты, переданные в качестве параметра, действуют как уникальный идентификатор, это никак не влияет на него.

3 голосов
/ 11 августа 2009

Как все здесь упоминают ...

  • замок - логическая концепция
  • блокировка блокирует только то, что находится в блоке кода в фигурных скобках.

Но чтобы дать вам краткое представление:

Блокировка

- это не что иное, как замена Monitor.Enter и Monitor.Exit. Именно с блокировкой Monitor.Exit помещается в блок finally.

Итак, что вы есть АКТУАЛЬНО блокировка - это (в вашем коде) объект блокировки. Таким образом, в любом месте вашего кода, если вы используете этот объект блокировки для блокировки, этот блок кода будет заблокирован.

Полагаю, так работает ваш замок: (Гуру, поправьте меня, если я ошибаюсь)

if(locker.SyncBlockIndex <0)>                                                       
{                                                                                
//obtain an index to free synch cache block                                      
//assign the index obtained in previous step to obj.SyncBlockIndex               
}                                                                                
syncblock = syncblockCache[locker.SyncBlockIndex]                                   
if(!syncblock is owned by the calling thread)                                    
{                                                                                
//susped the calling thread                                                      
}            

Посмотрите, поможет ли эта ссылка понять блокировку (я написал это сообщение некоторое время назад)

http://dotenetscribbles.blogspot.com/2008/10/calling-monitorenter-recursively.html

3 голосов
/ 11 августа 2009

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

В некоторых классах есть механизмы, позволяющие блокировать их в нескольких местах. Примером этого является свойство Syncroot Hashtable . Полезность этого вопроса сомнительна, хотя . Хорошая дискуссия об этом на SO .

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

2 голосов
/ 11 августа 2009

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

Вы также можете проверить ответы на этот вопрос: Блокирует ли () {} блокировку ресурса или блокирует фрагмент кода?

1 голос
/ 11 августа 2009

Краткий ответ: Нет

Блокировка - это логическая, а не физическая концепция, в которой язык / процессор определяет область действия блокировки и ограничивает доступ ко всем элементам в области действия. Ваша задача - обеспечить использование блокировки, поэтому, если вам нужно получить блокировку X для использования ресурса Y, вы должны всегда это делать.

1 голос
/ 11 августа 2009

Блокировка не относится к какому-либо объекту - она ​​относится только к фрагменту кода. Поэтому, если у вас есть две разные функции, которые работают с глобальным сокетом, вы должны контролировать их оба, для вашего примера это должен быть один и тот же объект «locker» - поэтому сделайте его видимым для обоих фрагментов кода.

...