¿Cuándo es apropiado usar la Monitor
clase o la lock
palabra clave para la seguridad de subprocesos en C #?
EDITAR:
Por las respuestas hasta ahora, parece que lock
es una forma abreviada de una serie de llamadas a la Monitor
clase. ¿Para qué sirve exactamente la llamada de bloqueo? O más explícitamente,
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 ?
}
}
Actualizar
Gracias a todos por su ayuda: he publicado otra pregunta como seguimiento de parte de la información que todos proporcionaron. Dado que parece estar bien versado en esta área, he publicado el enlace: ¿Qué tiene de malo esta solución para bloquear y administrar excepciones bloqueadas?
lock
bloque.Pulse
un bloqueo simple. Es importante en algunos escenarios avanzados de subprocesos múltiples. Nunca lo he usadoPulse
directamente.lock
es solo un atajo paraMonitor.Enter
contry
+finally
yMonitor.Exit
. Use la instrucción de bloqueo siempre que sea suficiente; si necesita algo como TryEnter, tendrá que usar Monitor.fuente
Una declaración de bloqueo es equivalente a:
Monitor.Enter(object); try { // Your code here... } finally { Monitor.Exit(object); }
Sin embargo, tenga en cuenta que Monitor también puede esperar () y Pulse () , que a menudo son útiles en situaciones complejas de subprocesos múltiples.
Actualizar
Sin embargo, en C # 4 se implementa de manera diferente:
bool lockWasTaken = false; var temp = obj; try { Monitor.Enter(temp, ref lockWasTaken); //your code } finally { if (lockWasTaken) Monitor.Exit(temp); }
Gracias a CodeInChaos por sus comentarios y enlaces
fuente
Monitor
es más flexible. Mi caso de uso favorito de usar el monitor es cuando no quiere esperar su turno y simplemente salta ://already executing? forget it, lets move on if(Monitor.TryEnter(_lockObject)) { //do stuff; Monitor.Exit(_lockObject); }
fuente
Como han dicho otros,
lock
es "equivalente" aMonitor.Enter(object); try { // Your code here... } finally { Monitor.Exit(object); }
Pero solo por curiosidad,
lock
conservará la primera referencia que le pase y no la tirará si la cambia. Sé que no se recomienda cambiar el objeto bloqueado y no quieres hacerlo.Pero de nuevo, para la ciencia, esto funciona bien:
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());
... Y esto no:
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());
Error:
Esto se debe a
Monitor.Exit(lockObject);
que actuará sobre lolockObject
que ha cambiado porquestrings
son inmutables, entonces lo estás llamando desde un bloque de código no sincronizado ... pero de todos modos. Este es solo un hecho divertido.fuente
object temp = lockObject; Monitor.Enter(temp); <...locked code...> Monitor.Exit(temp);
Ambos son lo mismo. lock es una palabra clave aguda y usa la clase Monitor.
http://msdn.microsoft.com/en-us/library/ms173179(v=vs.80).aspx
fuente
El bloqueo y el comportamiento básico del monitor (entrar + salir) es más o menos el mismo, pero el monitor tiene más opciones que te permite más posibilidades de sincronización.
El candado es un atajo y es la opción para el uso básico.
Si necesita más control, el monitor es la mejor opción. Puede utilizar Wait, TryEnter y Pulse, para usos avanzados (como barreras, semáforos, etc.).
fuente
Bloquear La palabra clave de bloqueo asegura que un hilo esté ejecutando un fragmento de código a la vez.
bloquear (lockObject)
{ // Body }
La palabra clave de bloqueo marca un bloque de instrucciones como una sección crítica al obtener el bloqueo de exclusión mutua para un objeto dado, ejecutar una instrucción y luego liberar el bloqueo.
Si otro hilo intenta ingresar un código bloqueado, esperará, se bloqueará, hasta que se libere el objeto.
Monitor El Monitor es una clase estática y pertenece al espacio de nombres System.Threading.
Proporciona un bloqueo exclusivo en el objeto para que solo un hilo pueda entrar en la sección crítica en un momento dado.
Diferencia entre supervisar y bloquear en C #
El candado es el atajo para Monitor. Ingrese con try y finalmente. Las manijas de bloqueo intentan y finalmente se bloquean internamente Bloquear = Supervisar + intentar finalmente.
Si desea tener más control para implementar soluciones avanzadas de subprocesos múltiples utilizando
TryEnter()
Wait()
,Pulse()
yPulseAll()
métodos, a continuación, la clase Monitor es su opción.C#
Monitor.wait()
: un subproceso espera a que otros subprocesos notifiquen.Monitor.pulse()
: Un hilo notifica a otro hilo.Monitor.pulseAll()
: Un hilo notifica a todos los demás hilos dentro de un procesofuente
Además de todas las explicaciones anteriores, lock es una declaración de C # mientras que Monitor es una clase de .NET ubicada en el espacio de nombres System.Threading.
fuente