2012-01-12 12 views
5

Puede Monitor.Enter lanzar cualquier excepción. Estoy haciendo una revisión del código y descubro que Monitor.Enter está antes del bloque try. ¿Ves algún problema con in?¿Puede Monitor.Enter lanzar una excepción?

Monitor.Enter(...) 
try 
{ 
    ... 
} 
finally 
{ 
    Monitor.Exit(..) 
} 
+3

Tener Enter() dentro del bloque try es un error. Llamarás a Exit() cuando podría no haber ingresado(). Solo tendría que sufrir un dolor de estómago por una excepción planteada * después de * la llamada Enter(), * antes de * ingresar al bloque try. Que de hecho era un error en la inestabilidad x64: http: //www.bluebytesoftware.com/blog/2007/01/30/MonitorEnterThreadAbortsAndOrphanedLocks.aspx También la motivación detrás de la nueva sobrecarga de 4.0 Monitor.Enter (object, ref bool). –

Respuesta

13

Este es el patrón correcto, si Enter() tiros (puede lanzar) o no.

Solo después de que la llamada al Enter() tenga éxito su código es bajo la responsabilidad de llamar al Exit().

Supongamos que la llamada a Enter() falla. Entonces llamar al Exit() correspondiente es simplemente incorrecto, empeorará las cosas. Entonces Enter() tiene que estar afuera (antes) del bloque try.

1

Monitor.Enter puede lanzar al menos las siguientes excepciones

  • ArgumentNullException del parámetro es null
  • ThreadInterruptedException si el hilo haciendo el Enter ha invocado se Interrupt método.
0

Si adquiere la cerradura, entonces no.

Pero puede haber una excepción entre el Monitor.Enter y el try bloque.

El método recomendado es el nuevo método Enter, nueva en .NET 4: comentario de

public static void Enter(obj, ref bool lockTaken) 
+0

Todavía lanzará 'ArgumentNullException'. – BoltClock

+0

@BoltClock Si no puede adquirir el bloqueo por alguna razón, 'lockTaken' será falso. –

10

Hans Passant es, por supuesto correcta. Si Monitor.Enter arroja antes de se toma la cerradura, entonces usted hace no quiere que finalmente se ejecute. Si arroja después de se toma el bloqueo y después de se ingresa la prueba, luego se libera el bloqueo. (Más sobre esto más adelante.) Pero si el lanzamiento ocurre después de que se toma el bloqueo pero antes de se ingresa la prueba, y luego el bloqueo nunca se limpiará.

This is a rare but possible situation.

En C# 4 cambiamos el codegen de la declaración de bloqueo para que el monitor ingrese está dentro del intento. Esto asegura que el bloqueo siempre se libera si algo se lanza después de que se realiza el bloqueo. Sin embargo, tenga en cuenta que esto aún podría estar equivocado. Si se lanza algo después de que se haya activado el bloqueo, entonces ¡cualquiera que sea la mutación no atómica que protege el bloqueo puede completarse a medias, y el bloque finally desbloquea el bloqueo y permite el acceso al estado incoherente! El problema fundamental aquí es que no deberías tirar dentro de un candado en primer lugar.

Consulte my article about the issue para obtener más información.

+0

Me encantaría obtener un mecanismo más general que funcione en pares personalizados 'Entrar/Salir' también. La instrucción 'using' actual, que a menudo se usa para esto, sufre el mismo problema que la declaración de bloqueo anterior. – CodesInChaos

+0

@CodeInChaos: Pero la diferencia es que lo peor que debería suceder si un lanzamiento ocurre en el lugar equivocado y un recurso no administrado asignado no se limpia de manera oportuna si alguien no puede usar ese recurso. Un bloqueo que se limpia cuando el estado del objeto bloqueado es inconsistente es un problema de corrección, no un problema de cortesía. –

+0

Un patrón general, seguro "Entrar/Salir" tendría aplicaciones más allá de simplemente liberar recursos inseguros. He visto declaraciones 'using' para el bloqueo personalizado, las transacciones de la base de datos, ... El bloqueo personalizado se beneficiaría mucho de tal característica, por lo que finalmente es seguro y conveniente. Personalmente, creo que la versión actual de la declaración 'lock' no debería existir en primer lugar, sino que debe expresarse utilizando una característica más general. Pero es demasiado tarde para cambiar eso ahora. – CodesInChaos

Cuestiones relacionadas