En la aplicación de subprocesos ac #, si tuviera que bloquear un objeto, digamos una cola, y si ocurre una excepción, ¿el objeto permanecerá bloqueado? Aquí está el pseudocódigo:
int ii;
lock(MyQueue)
{
MyClass LclClass = (MyClass)MyQueue.Dequeue();
try
{
ii = int.parse(LclClass.SomeString);
}
catch
{
MessageBox.Show("Error parsing string");
}
}
Según tengo entendido, el código después de la captura no se ejecuta, pero me he estado preguntando si se liberará el bloqueo.
Respuestas:
Primero; ¿ha considerado TryParse?
in li; if(int.TryParse(LclClass.SomeString, out li)) { // li is now assigned } else { // input string is dodgy }
El bloqueo se liberará por 2 razones; primero,
lock
es esencialmente:Monitor.Enter(lockObj); try { // ... } finally { Monitor.Exit(lockObj); }
Segundo; detecta y no vuelve a lanzar la excepción interna, por lo que
lock
nunca ve una excepción. Por supuesto, mantendrá el bloqueo durante la duración de un MessageBox, lo que podría ser un problema.Por lo tanto, se publicará en todas las excepciones, excepto en las catastróficas irrecuperables más fatales.
fuente
TheadAbortException
produce entreMonitor.Enter
ytry
: blogs.msdn.com/ericlippert/archive/2009/03/06/…Observo que nadie ha mencionado en sus respuestas a esta vieja pregunta que liberar un candado en una excepción es algo increíblemente peligroso. Sí, las sentencias de bloqueo en C # tienen semántica "finalmente"; cuando el control sale de la cerradura de forma normal o anormal, la cerradura se libera. Todos están hablando de esto como si fuera algo bueno, ¡pero es algo malo! Lo correcto si tiene una región bloqueada que arroja una excepción no controlada es terminar el proceso enfermo inmediatamente antes de que destruya más datos de usuario , no liberar el bloqueo y continuar .
Mírelo de esta manera: suponga que tiene un baño con una cerradura en la puerta y una fila de gente esperando afuera. Una bomba estalla en el baño, matando a la persona que está allí. Su pregunta es "en esa situación, ¿se desbloqueará automáticamente la cerradura para que la siguiente persona pueda entrar al baño?" Sí, lo hará. Eso no es algo bueno. ¡Una bomba estalló allí y mató a alguien! Es probable que la tubería esté destruida, la casa ya no sea estructuralmente sólida y podría haber otra bomba allí . Lo correcto es sacar a todos lo más rápido posible y demoler toda la casa.
Quiero decir, piénselo bien: si bloqueó una región de código para leer desde una estructura de datos sin que se mute en otro hilo, y algo en esa estructura de datos arrojó una excepción, es muy probable que sea porque la estructura de datos está corrupto . Los datos del usuario ahora están desordenados; no desea intentar guardar datos de usuario en este momento porque luego está guardando datos corruptos . Simplemente finalice el proceso.
Si bloqueó una región de código para realizar una mutación sin que otro hilo leyera el estado al mismo tiempo, y la mutación se produce, entonces si los datos no estaban corruptos antes, seguro que lo están ahora . Cuál es exactamente el escenario contra el que se supone que protege la cerradura . Ahora, el código que está esperando leer ese estado tendrá acceso inmediato al estado corrupto y probablemente se bloqueará. Nuevamente, lo correcto es terminar el proceso.
No importa cómo lo corte, una excepción dentro de una cerradura es una mala noticia . La pregunta correcta no es "¿se limpiará mi cerradura en caso de una excepción?" La pregunta correcta es "¿cómo me aseguro de que nunca haya una excepción dentro de una cerradura? Y si la hay, ¿cómo puedo estructurar mi programa para que las mutaciones se reviertan a estados buenos anteriores?"
fuente
sí, se lanzará correctamente;
lock
actúa comotry
/finally
, con elMonitor.Exit(myLock)
en el finalmente, así que no importa cómo salga, se liberará. Como nota al margen,catch(... e) {throw e;}
es mejor evitarlo, ya que eso daña el seguimiento de la pila ene
; es mejor no atraparlo en absoluto , o alternativamente: usar enthrow;
lugar dethrow e;
cuál hace un relanzamiento.Si realmente quiere saberlo, un bloqueo en C # 4 / .NET 4 es:
{ bool haveLock = false; try { Monitor.Enter(myLock, ref haveLock); } finally { if(haveLock) Monitor.Exit(myLock); } }
fuente
"Se compila una declaración de bloqueo para una llamada a Monitor.Enter, y luego un intento ... bloquear finalmente. En el bloque finalmente, se llama a Monitor.Salir.
La generación de código JIT para x86 y x64 asegura que no se pueda producir un aborto de subproceso entre una llamada Monitor.Enter y un bloque try que le sigue inmediatamente ".
Tomado de: Este sitio
fuente
Monitor.Enter
y eltry
, de modo que la condición "sigue inmediatamente" del Se infringe el JIT.Su cerradura se liberará correctamente. A
lock
actúa así:try { Monitor.Enter(myLock); // ... } finally { Monitor.Exit(myLock); }
Y los
finally
bloques están garantizados para ejecutarse, sin importar cómo salga deltry
bloque.fuente
Solo para agregar un poco a la excelente respuesta de Marc.
Situaciones como esta son la verdadera razón de la existencia de la
lock
palabra clave. Ayuda a los desarrolladores a asegurarse de que el bloqueo se libere en elfinally
bloque.Si se ve obligado a usar
Monitor.Enter
/Exit
eg para admitir un tiempo de espera, debe asegurarse de colocar la llamada aMonitor.Exit
en elfinally
bloque para garantizar la liberación adecuada del bloqueo en caso de una excepción.fuente