Quando é apropriado usar a Monitor
classe ou a lock
palavra - chave para segurança de thread em C #?
EDITAR:
Parece pelas respostas até agora que lock
é um atalho para uma série de ligações para a Monitor
classe. Para que exatamente é a abreviação de chamada de bloqueio? Ou mais explicitamente,
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 ?
}
}
Atualizar
Obrigado a todos por sua ajuda: Eu postei outra pergunta como um acompanhamento de algumas das informações que todos vocês forneceram. Como você parece ser bem versado nessa área, postei o link: O que há de errado com essa solução para bloquear e gerenciar exceções bloqueadas?
lock
bloco.Pulse
de um bloqueio simples. É importante em alguns cenários avançados de multithread. Nunca useiPulse
diretamente.lock
é apenas um atalho paraMonitor.Enter
comtry
+finally
eMonitor.Exit
. Use a instrução de bloqueio sempre que for suficiente - se você precisar de algo como TryEnter, terá que usar o Monitor.fonte
Uma instrução de bloqueio é equivalente a:
Monitor.Enter(object); try { // Your code here... } finally { Monitor.Exit(object); }
No entanto, lembre-se de que Monitor também pode Wait () e Pulse () , que geralmente são úteis em situações complexas de multithreading.
Atualizar
No entanto, em C # 4 é implementado de forma diferente:
bool lockWasTaken = false; var temp = obj; try { Monitor.Enter(temp, ref lockWasTaken); //your code } finally { if (lockWasTaken) Monitor.Exit(temp); }
Agradecimentos a CodeInChaos pelos comentários e links
fonte
Monitor
é mais flexível. Meu caso de uso favorito de usar monitor é quando você não quer esperar pela sua vez e apenas pular ://already executing? forget it, lets move on if(Monitor.TryEnter(_lockObject)) { //do stuff; Monitor.Exit(_lockObject); }
fonte
Como outros já disseram,
lock
é "equivalente" aMonitor.Enter(object); try { // Your code here... } finally { Monitor.Exit(object); }
Mas só por curiosidade,
lock
preservará a primeira referência que você passar para ele e não jogará se você alterar. Eu sei que não é recomendado mudar o objeto bloqueado e você não quer fazer isso.Mas, novamente, para a ciência, isso funciona bem:
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());
... E isso não:
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());
Erro:
Isso ocorre porque
Monitor.Exit(lockObject);
vai agir sobre olockObject
que mudou porquestrings
são imutáveis, então você está chamando de um bloco de código não sincronizado ... mas de qualquer maneira. Este é apenas um fato divertido.fonte
object temp = lockObject; Monitor.Enter(temp); <...locked code...> Monitor.Exit(temp);
Ambos são a mesma coisa. lock é uma palavra-chave c sharp e usa a classe Monitor.
http://msdn.microsoft.com/en-us/library/ms173179(v=vs.80).aspx
fonte
O bloqueio e o comportamento básico do monitor (entrar + sair) são mais ou menos iguais, mas o monitor tem mais opções que permitem mais possibilidades de sincronização.
O bloqueio é um atalho e é a opção para o uso básico.
Se você precisar de mais controle, o monitor é a melhor opção. Você pode usar o Wait, TryEnter e o Pulse, para usos avançados (como barreiras, semáforos e assim por diante).
fonte
A palavra-chave Lock Lock garante que um thread esteja executando um trecho de código por vez.
lock (lockObject)
{ // Body }
A palavra-chave lock marca um bloco de instrução como uma seção crítica, obtendo o bloqueio de exclusão mútua para um determinado objeto, executando uma instrução e liberando o bloqueio
Se outro thread tentar inserir um código bloqueado, ele aguardará, bloqueará, até que o objeto seja liberado.
Monitor O Monitor é uma classe estática e pertence ao namespace System.Threading.
Ele fornece bloqueio exclusivo no objeto para que apenas um thread possa entrar na seção crítica em qualquer ponto do tempo.
Diferença entre monitorar e bloquear em C #
O bloqueio é o atalho para Monitor.Enter com try e finalmente. As alças de bloqueio tentam e bloqueiam internamente .
Se você quiser mais controle para implementar soluções avançadas de multithreading usando
TryEnter()
Wait()
,Pulse()
ePulseAll()
métodos, então a classe Monitor é a sua opção.C #
Monitor.wait()
: um thread aguarda a notificação de outros threads.Monitor.pulse()
: Um tópico é notificado para outro tópico.Monitor.pulseAll()
: Um thread notifica todos os outros threads dentro de um processofonte
Além de todas as explicações acima, lock é uma instrução C # enquanto Monitor é uma classe de .NET localizada no namespace System.Threading.
fonte