Monitor contra locking

¿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 locking 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?

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 locking.


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 comstackdor insertó un NOP entre ellos y, por lo tanto, hizo abortar el hilo entre los posibles.

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

Una instrucción de locking 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

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(); 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(); 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.

Ambos son lo mismo. lock es la palabra clave c sharp y usa la clase Monitor.

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

El locking 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 locking 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.).

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); }