www w3org spec section official etiquetas c# .net multithreading locking monitor

c# - w3org - w3c etiquetas html



Monitor contra bloqueo (7)

¿Cuándo es apropiado utilizar la clase Monitor o la palabra clave de lock para la seguridad de subprocesos en C #?

EDITAR: Parece de las respuestas hasta ahora que el lock es corto para una serie de llamadas a la clase Monitor . ¿Para qué sirve exactamente la llamada de bloqueo para abreviar? 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 proporcionaron. Dado que usted parece estar bien versado en esta área, he publicado el enlace: ¿Qué tiene de malo esta solución para bloquear y administrar excepciones bloqueadas?



Como otros han dicho, el lock es "equivalente" a

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

Pero solo por curiosidad, el lock conservará la primera referencia que le pase y no lo arrojará si lo cambia. Sé que no se recomienda cambiar el objeto bloqueado y no quieres hacerlo.

Pero, nuevamente, 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:

Se produjo una excepción de tipo ''System.Threading.SynchronizationLockException'' en 70783sTUDIES.exe pero no se manejó en el código de usuario

Información adicional: se llamó al método de sincronización de objetos desde un bloque de código no sincronizado.

Esto es porque Monitor.Exit(lockObject); actuará en lockObject que ha cambiado porque las strings son inmutables, entonces lo está llamando desde un bloque de código no sincronizado ... pero de todos modos. Esto es solo un hecho divertido.


El bloqueo y el comportamiento básico del monitor (ingresar + salir) es más o menos el mismo, pero el monitor tiene más opciones que le permiten más posibilidades de sincronización.

El bloqueo 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 usar Wait, TryEnter y Pulse, para usos avanzados (como barreras, semáforos, etc.).


Eric Lippert habla de esto en su blog: las cerraduras y las excepciones no se mezclan

El código equivalente difiere entre C # 4.0 y versiones anteriores.

En C # 4.0 es:

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

Se basa en Monitor.Enter atómicamente estableciendo el indicador cuando se realiza el bloqueo.

Y antes fue:

var temp = obj; Monitor.Enter(temp); try { body } finally { Monitor.Exit(temp); }

Esto se basa en que no se lanza ninguna excepción entre Monitor.Enter y el try . Creo que en el código de depuración esta condición se violó porque el compilador insertó un NOP entre ellos y, por lo tanto, hizo abortar el hilo entre los posibles.


Una instrucció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 Pulsar () , que a menudo son útiles en situaciones complejas de subprocesamiento múltiple.

Actualizar

Sin embargo, en C # 4 se implementó 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


Monitor es más flexible. Para mí, el caso favorito de usar monitor es cuando no quieres esperar tu turno, y solo saltas :

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


lock es solo un atajo para Monitor.Enter con try + finally y Monitor.Exit . Use la instrucción de bloqueo cada vez que sea suficiente; si necesita algo como TryEnter, tendrá que usar Monitor.