Когда в C # целесообразно использовать Monitor
класс или lock
ключевое слово для обеспечения безопасности потоков?
РЕДАКТИРОВАТЬ:
Судя по ответам до сих пор, 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 ?
}
}
Обновить
Спасибо всем за вашу помощь: я опубликовал еще один вопрос в продолжение некоторой информации, которую вы все предоставили. Поскольку вы, кажется, хорошо разбираетесь в этой области, я разместил ссылку: Что плохого в этом решении для блокировки и управления заблокированными исключениями?
lock
блока.Pulse
простая блокировка. Это важно в некоторых сложных сценариях многопоточности. Я никогда не использовалPulse
напрямую.lock
это просто ярлыкMonitor.Enter
сtry
+finally
иMonitor.Exit
. Используйте оператор блокировки всякий раз, когда этого достаточно - если вам нужно что-то вроде TryEnter, вам придется использовать Monitor.источник
Оператор блокировки эквивалентен:
Monitor.Enter(object); try { // Your code here... } finally { Monitor.Exit(object); }
Однако имейте в виду, что Monitor может также Wait () и Pulse () , которые часто полезны в сложных многопоточных ситуациях.
Обновить
Однако в C # 4 это реализовано иначе:
bool lockWasTaken = false; var temp = obj; try { Monitor.Enter(temp, ref lockWasTaken); //your code } finally { if (lockWasTaken) Monitor.Exit(temp); }
Спасибо CodeInChaos за комментарии и ссылки
источник
Monitor
более гибкий. Мой любимый вариант использования монитора - это когда вы не хотите ждать своей очереди и просто пропустите ://already executing? forget it, lets move on if(Monitor.TryEnter(_lockObject)) { //do stuff; Monitor.Exit(_lockObject); }
источник
Как говорили другие,
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());
Ошибка:
Это потому, что
Monitor.Exit(lockObject);
будет действовать то,lockObject
что было изменено, потому чтоstrings
они неизменяемы, тогда вы вызываете его из несинхронизированного блока кода ... но в любом случае. Это просто забавный факт.источник
object temp = lockObject; Monitor.Enter(temp); <...locked code...> Monitor.Exit(temp);
Оба - одно и то же. lock - ключевое слово c sharp и использовать класс Monitor.
http://msdn.microsoft.com/en-us/library/ms173179(v=vs.80).aspx
источник
Блокировка и основное поведение монитора (ввод + выход) более или менее одинаковы, но у монитора есть больше опций, которые позволяют вам больше возможностей синхронизации.
Блокировка - это ярлык, и это вариант для базового использования.
Если вам нужно больше контроля, монитор - лучший вариант. Вы можете использовать Wait, TryEnter и Pulse для расширенного использования (например, барьеры, семафоры и т. Д.).
источник
Lock Ключевое слово Lock гарантирует, что один поток одновременно выполняет часть кода.
блокировка (lockObject)
{ // Body }
Ключевое слово lock помечает блок инструкций как критическую секцию, получая блокировку взаимного исключения для данного объекта, выполняя инструкцию и затем снимая блокировку.
Если другой поток пытается ввести заблокированный код, он будет ждать, блокировать, пока объект не будет освобожден.
Монитор Монитор - это статический класс, принадлежащий пространству имен System.Threading.
Он обеспечивает исключительную блокировку объекта, так что только один поток может войти в критическую секцию в любой момент времени.
Разница между монитором и блокировкой в C #
Блокировка - это ярлык для Monitor.Enter с помощью try и finally. Блокировать дескрипторы пытаются и, наконец, заблокировать внутренне Lock = Monitor + try finally.
Если вы хотите больше контроля , чтобы реализовать передовую многопоточность решения с использованием
TryEnter()
Wait()
,Pulse()
иPulseAll()
метод, то класс Monitor вашего вариант.C #
Monitor.wait()
: поток ожидает уведомления других потоков.Monitor.pulse()
: Поток уведомляет другой поток.Monitor.pulseAll()
: Поток уведомляет все другие потоки в процессеисточник
В дополнение ко всем приведенным выше объяснениям, lock - это оператор C #, тогда как Monitor - это класс .NET, расположенный в пространстве имен System.Threading.
источник