Как работает блокировка? - PullRequest
455 голосов
/ 17 мая 2011

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

private static readonly Object obj = new Object();

lock (obj)
{
    // thread unsafe code
}

Так что же происходит, когда несколько потоков обращаются к одному и тому же коду (предположим, что он выполняется в веб-приложении ASP.NET). Они в очереди? Если так, то как долго они будут ждать?

Какое влияние на производительность оказывает использование блокировок?

Ответы [ 8 ]

404 голосов
/ 17 мая 2011

Оператор lock переведен C # 3.0 в следующее:

var temp = obj;

Monitor.Enter(temp);

try
{
    // body
}
finally
{
    Monitor.Exit(temp);
}

В C # 4.0 это изменилось , и теперь оно генерируется следующим образом:

bool lockWasTaken = false;
var temp = obj;
try
{
    Monitor.Enter(temp, ref lockWasTaken);
    // body
}
finally
{
    if (lockWasTaken)
    {
        Monitor.Exit(temp); 
    }
}

Вы можете найти больше информации о том, что Monitor.Enter делает здесь . Цитировать MSDN:

Используйте Enter, чтобы получить монитор на объект передан в качестве параметра. Если другой поток выполнил Enter на объекте, но еще не выполнено соответствующий Exit, текущий поток будет блокировать, пока другой поток освобождает объект. это законно для того же потока, чтобы вызвать Enter более одного раза без него блокирование; однако равное количество Exit звонки должны быть вызваны до другие потоки, ожидающие на объекте разблокирует.

Метод Monitor.Enter будет ждать бесконечно; не будет время ожидания.

238 голосов
/ 10 апреля 2014

Это проще, чем вы думаете.

Согласно Microsoft : Ключевое слово lock гарантирует, что один поток не войдет в критический раздел кода, в то время как другой поток находится в критическом разделе. Если другой поток попытается ввести заблокированный код, он будет ждать блокировки до тех пор, пока объект не будет освобожден.

Ключевое слово lock вызывает Enter в начале блока и Exit в конце блока. Ключевое слово lock фактически обрабатывает Monitor класс на заднем конце.

Например:

private static readonly Object obj = new Object();

lock (obj)
{
    // critical section
}

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

43 голосов
/ 17 мая 2011

Нет, они не стоят в очереди, они спят

Оператор блокировки вида

lock (x) ... 

где x является выражением ссылочного типа, точно эквивалентно

var temp = x;
System.Threading.Monitor.Enter(temp); 
try { ... } 
finally { System.Threading.Monitor.Exit(temp); }

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

Монитор полностью записан в .net, поэтому он достаточно быстр, также посмотрите монитор класса с отражателем для получения более подробной информации

26 голосов
/ 17 мая 2011

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

10 голосов
/ 17 мая 2011

Влияние на производительность зависит от способа блокировки. Вы можете найти хороший список оптимизаций здесь: http://www.thinkingparallel.com/2007/07/31/10-ways-to-reduce-lock-contention-in-threaded-programs/

По сути, вы должны попытаться заблокировать как можно меньше, так как это переводит ваш код ожидания в спящий режим. Если у вас есть некоторые тяжелые вычисления или длительный код (например, загрузка файла) в блокировке, это приводит к огромной потере производительности.

7 голосов
/ 17 мая 2011

Оператор lock преобразуется в вызовы методов Enter и Exit Monitor.

Оператор lock будет бесконечно ожидать блокировкиобъект, который будет выпущен.

7 голосов
/ 17 мая 2011

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

4 голосов
/ 17 мая 2011

блокировка фактически скрыта Монитор класс.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...