Как работает блокировка?

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

private static readonly Object obj = new Object();

lock (obj)
{
    // thread unsafe code
}

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

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

Ответ 1

Оператор lock переведен на С# 3.0 следующим образом:

var temp = obj;

Monitor.Enter(temp);

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

В С# 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 будет бесконечно ждать; он не будет тайм-аут.

Ответ 2

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

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

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

Например:

private static readonly Object obj = new Object();

lock (obj)
{
    // critical section
}

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

Ответ 3

Нет, они не поставлены в очередь, они спали

Оператор блокировки формы

lock (x) ... 

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

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

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

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

Ответ 4

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

Ответ 5

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

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

Ответ 6

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

Ответ 7

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

Оператор lock будет ждать неограниченное время для освобождения объекта блокировки.

Ответ 9

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

статический объект только для чтения obj = new object(); public static Singleton GetInstance {get {if (instance == null) {lock (obj) {if (instance == null) {instance = new Singleton(); } } } return instance; }}} return instance;

        }
    }