Монитор против замка



Когда уместно использовать класс 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 ?
    }
}

Обновить

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

201   7  

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, вам придется использовать монитор.

Оператор блокировки эквивалентен:

Monitor.Enter(object);
try
{
   // Your code here...
}
finally
{
   Monitor.Exit(object);
}
Однако имейте в виду, что монитор может также Wait() и Pulse(), которые часто полезны в сложных многопоточных ситуациях.

Обновить

Однако в 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);
}
    Ничего не найдено.

Добавить ответ:
Отменить.