it-swarm-ru.tech

Монитор против блокировки

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

Update

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

80
smartcaveman

Эрик Липперт говорит об этом в своем блоге: Замки и исключения не смешиваются

Эквивалентный код отличается между 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. Я думаю, что в коде отладки это условие было нарушено, потому что компилятор вставил NOP между ними и таким образом сделал прерывание потока между ними возможным.

81
CodesInChaos

lock - это просто сокращение для Monitor.Enter с try + finally и Monitor.Exit. Используйте оператор блокировки всякий раз, когда этого достаточно - если вам нужно что-то вроде TryEnter, вам придется использовать Monitor.

37
Lukáš Novotný

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

Monitor.Enter(object);
try
{
   // Your code here...
}
finally
{
   Monitor.Exit(object);
}

Однако имейте в виду, что Monitor также может Wait () и Pulse () , которые часто полезны в сложных многопоточных ситуациях.

Update

Однако в C # 4 это реализовано по-другому:

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

Спасибо CodeInChaos за комментарии и ссылки

20
Shekhar_Pro

Monitor более гибок. Для меня любимым случаем использования монитора является когда вы не хотите ждать своей очереди и просто пропустить:

//already executing? eff it, lets move on
if(Monitor.TryEnter(_lockObject))
{
    //do stuff;
    Monitor.Exit(_lockObject);
}
6
Alex

Как уже говорили другие, 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.Threading.SynchronizationLockException" возникло в 70783sTUDIES.exe, но не было обработано в коде пользователя

Дополнительная информация: Метод синхронизации объекта был вызван из несинхронизированного блока кода.

Это потому, что Monitor.Exit(lockObject); будет действовать на lockObject, который изменился, потому что strings неизменны, тогда вы вызываете его из несинхронизированного блока кода ... но в любом случае. Это просто забавный факт.

6
André Pena

Оба это одно и то же. Блокировка c острым ключевым словом и использовать класс монитора.

http://msdn.Microsoft.com/en-us/library/ms173179 (v = vs.80) .aspx

4
RobertoBr

Блокировка и основное поведение монитора (ввод + выход) более или менее одинаковы, но у монитора есть больше опций, которые дают вам больше возможностей для синхронизации.

Блокировка является ярлыком, и это вариант для базового использования.

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

3
Borja