Respostas:
lock
é uma palavra-chave do compilador, não uma classe ou objeto real. É um invólucro da funcionalidade da Monitor
classe e foi projetado para facilitar o Monitor
trabalho no caso comum.
O Monitor
(e a lock
palavra - chave) são, como Darin disse, restritos ao AppDomain
. Principalmente porque é necessária uma referência a um endereço de memória (na forma de um objeto instanciado) para gerenciar o "bloqueio" e manter a identidade doMonitor
O Mutex
, por outro lado, é um invólucro .Net em torno de uma construção de sistema operacional e pode ser usado para sincronização em todo o sistema, usando dados de string (em vez de um ponteiro para dados) como seu identificador. Dois mutexes que referenciam duas seqüências de caracteres em dois endereços de memória completamente diferentes, mas com os mesmos dados , realmente utilizarão o mesmo mutex do sistema operacional.
A Mutex
pode ser local para um processo ou para todo o sistema . MSDN :
Mutexes são de dois tipos: mutexes locais, sem nome, e nomeados mutexes do sistema. Um mutex local existe apenas dentro do seu processo.
Além disso, deve-se ter um cuidado especial - detalhado também na mesma página - ao usar um mutex em todo o sistema em um sistema com os Serviços de Terminal.
Uma das diferenças entre Mutex
e lock
é que Mutex
utiliza uma construção no nível do kernel , portanto, a sincronização sempre exigirá pelo menos uma transição de espaço do usuário para o espaço do kernel.
lock
- isso é realmente um atalho para a Monitor
classe , por outro lado, tenta evitar a alocação de recursos do kernel e a transição para o código do kernel (e, portanto, é mais enxuto e rápido - se for necessário encontrar uma construção WinAPI com a qual ela se assemelha CriticalSection
).
A outra diferença é o que os outros apontam: uma lata nomeada Mutex
ser usado entre processos.
A menos que alguém tenha necessidades especiais ou exija sincronização entre processos, é melhor se ater a lock
(aka Monitor
) ˛
Existem várias outras diferenças "menores", como a maneira como o abandono é tratado, etc.
O mesmo pode ser dito sobre ReaderWriterLock
e ReaderWriterLockSlim
no 3.5, Semaphore
e o novo SemaphoreSlim
no .NET 4.0 etc. É verdade que as últimas xxSlim
classes não podem ser usadas como primitivas de sincronização em todo o sistema, mas nunca foram feitas para isso - elas foram "apenas" para ser mais rápido e mais amigável aos recursos.
Eu uso um Mutex para verificar se eu já tenho uma cópia do aplicativo em execução na mesma máquina.
bool firstInstance;
Mutex mutex = new Mutex(false, @"Local\DASHBOARD_MAIN_APPLICATION", out firstInstance);
if (!firstInstance)
{
//another copy of this application running
}
else
{
//run main application loop here.
}
// Refer to the mutex down here so garbage collection doesn't chuck it out.
GC.KeepAlive(mutex);
Muito já foi dito, mas para simplificar, aqui está minha opinião.
lock -> Simples de usar, wrapper no monitor, bloqueia os threads em um AppDomain.
mutex sem nome -> semelhante ao bloqueio, exceto que o escopo de bloqueio é maior e está no AppDomain em um processo.
O mutex nomeado -> o escopo de bloqueio é ainda mais do que o mutex não nomeado e está em processo no sistema operacional.
Portanto, agora existem opções, você precisa escolher a que melhor se adapta ao seu caso.
O Mutex é um processo cruzado e haverá um exemplo clássico de não executar mais de uma instância de um aplicativo.
O segundo exemplo é que você está tendo um arquivo e não deseja que processos diferentes acessem o mesmo arquivo, você pode implementar um Mutex, mas lembre-se de uma coisa: o Mutex é um sistema operacional amplo e não pode ser usado entre dois processos remotos.
O bloqueio é uma maneira mais simples de proteger a seção do seu código e é específico do domínio do aplicativo. Você pode substituir o bloqueio pelo Moniters se desejar uma sincronização mais controlada.
Mais algumas pequenas diferenças que não foram mencionadas nas respostas:
No caso de usar bloqueios, você pode ter certeza de que o bloqueio será liberado quando ocorrer uma exceção dentro do bloco do bloqueio.
Isso ocorre porque o bloqueio usa monitores sob o capô e é implementado desta maneira:
object __lockObj = x;
bool __lockWasTaken = false;
try
{
System.Threading.Monitor.Enter(__lockObj, ref __lockWasTaken);
// Your code...
}
finally
{
if (__lockWasTaken) System.Threading.Monitor.Exit(__lockObj);
}
Portanto, em qualquer caso, o bloqueio é liberado e você não precisa liberá-lo manualmente (como faria nos mutexes).
Para bloqueios, você geralmente usa um objeto privado para bloquear (e deve usar ).
Isso é feito por vários motivos. (Mais informações: consulte esta resposta e documentação oficial ).
Portanto, no caso de bloqueios, você não pode (acidentalmente obter) acesso ao objeto bloqueado do lado de fora e causar alguns danos.
Mas no caso do Mutex, você pode, como é comum ter um Mutex que é marcado como público e usado de qualquer lugar.