Монитор против замка
Когда уместно использовать класс Monitor или ключевое слово lock для потокобезопасности в C#?
Редактировать:
Судя по ответам до сих пор, lock - это короткая рука для серии вызовов класса Monitor. Что именно замок звонок короткий-руку? Или более явно,
class LockVsMonitor
{
private readonly object LockObject = new object();
public void DoThreadSafeSomethingWithLock(Action action)
{
lock (LockObject)
{
action.Invoke();
}
}
public void DoThreadSafeSomethingWithMonitor(Action action)
{
// What goes here ?
}
}
Обновить
Спасибо всем за вашу помощь : я опубликовал еще один вопрос в дополнение к некоторой информации, которую вы все предоставили. С тех пор, как ты, кажется, хорошо разбираясь в этой области, я разместил ссылку: Что плохого в этом решении для блокировки и управления заблокированными исключениями?
7 ответов:
Эрик Липперт рассказывает об этом в своем блоге: блокировки и исключения не смешиваются
Эквивалентный код отличается между C# 4.0 и более ранними версиями.
В C# 4.0 это:
bool lockWasTaken = false; var temp = obj; try { Monitor.Enter(temp, ref lockWasTaken); { body } } finally { if (lockWasTaken) Monitor.Exit(temp); }Он полагается на
Monitor.Enterатомарную установку флага при взятии блокировки.
А раньше было:
var temp = obj; Monitor.Enter(temp); try { body } finally { Monitor.Exit(temp); }Это зависит от того, что между
Monitor.Enterиtryне возникает исключений. Я думаю, что в отладочном коде это условие было нарушено, потому что компилятор вставил НОП между ними и, таким образом, сделал аборт нити между теми возможными.
lockэто просто ярлык дляMonitor.Enterсtry+finallyиMonitor.Exit. Используйте оператор блокировки всякий раз, когда этого достаточно - если вам нужно что-то вроде TryEnter, вам придется использовать монитор.
Оператор блокировки эквивалентен:
Однако имейте в виду, что монитор может также Wait() и Pulse(), которые часто полезны в сложных многопоточных ситуациях.Monitor.Enter(object); try { // Your code here... } finally { Monitor.Exit(object); }Обновить
Однако в C# 4 он реализован иначе:
bool lockWasTaken = false; var temp = obj; try { Monitor.Enter(temp, ref lockWasTaken); //your code } finally { if (lockWasTaken) Monitor.Exit(temp); }Thanx к CodeInChaos для комментариев и ссылок
Как говорили другие,
lock"эквивалентно"Но просто из любопытства,Monitor.Enter(object); try { // Your code here... } finally { Monitor.Exit(object); }lockсохранит первую ссылку, которую вы передадите ему, и не бросит, если вы ее измените. я знаю, что не рекомендуется менять заблокированный объект , и вы не хотите этого делать. Но опять же, для науки это прекрасно работает:var lockObject = ""; var tasks = new List<Task>(); for (var i = 0; i < 10; i++) tasks.Add(Task.Run(() => { Thread.Sleep(250); lock (lockObject) { lockObject += "x"; } })); Task.WaitAll(tasks.ToArray());...И это не значит:
var lockObject = ""; var tasks = new List<Task>(); for (var i = 0; i < 10; i++) tasks.Add(Task.Run(() => { Thread.Sleep(250); Monitor.Enter(lockObject); try { lockObject += "x"; } finally { Monitor.Exit(lockObject); } })); Task.WaitAll(tasks.ToArray());Ошибка:
Исключение типа ' System.Нарезка резьбы.SynchronizationLockException' произошло это в 70783студиях.exe, но не был обработан в пользовательском коде
Дополнительная информация: метод синхронизации объектов был вызван из несинхронизированный блок кода.
Это потому, что
Monitor.Exit(lockObject);будет действовать наlockObject, который изменился, потому чтоstringsнеизменяемы, то вы вызываете его из несинхронизированного блока кода.. но все равно. Это просто забавный факт.
И то и другое-одно и то же. lock-это ключевое слово c sharp и класс Use Monitor.
Http://msdn.microsoft.com/en-us/library/ms173179 (v=против 80).aspx
Блокировка и основное поведение монитора (вход + выход) более или менее одинаковы, но монитор имеет больше опций, что позволяет вам больше возможностей синхронизации.
Блокировка-это ярлык, и это опция для основного использования.
Если вам нужно больше контроля, монитор-лучший вариант. Вы можете использовать Wait, TryEnter и Pulse для продвинутых применений (таких как барьеры, семафоры и т. д.).
Monitorболее гибок. Для меня любимый случай использования монитора-это , Когда вы не хотите ждать своей очереди, а просто пропускаете ://already executing? eff it, lets move on if(Monitor.TryEnter(_lockObject)) { //do stuff; Monitor.Exit(_lockObject); }
Comments