¿Cómo puedo detectar una ThreadAbortException en un bloque finally? (.RED)

votos
8

Tengo una lógica crítica en un bloque finally (con un bloque try vacío), porque quiero garantizar que el código se ejecute incluso si el hilo se cancela. Sin embargo, también me gustaría detectar ThreadAbortException. Descubrí que al envolver mi bloque try / finally crítico en try / catch no se detecta ThreadAbortException. ¿Hay alguna forma de detectarlo?

tratar {
    tratar { }
    finalmente {
        // lógica crítica
    }
} catch (Exception ex) {
    // ThreadAbortException no se captura aquí, pero se lanzan excepciones
    // desde dentro de la lógica crítica son
}
Publicado el 09/12/2008 a las 17:02
fuente por usuario
En otros idiomas...                            


7 respuestas

votos
8

Este es un problema curioso.

El código que envió debe trabajar. Parece que hay algún tipo de optimización en curso que decide no llamar a su controlador catch.

Por lo tanto, quería detectar la excepción con esto:

bool threadAborted = true;
try {
  try { }
  finally { /* critical code */ }
  threadAborted = false;
}
finally {
  Console.WriteLine("Thread aborted? {0}", threadAborted);
}
Console.WriteLine("Done");

(Mi código actual simplemente dormía en esa sección código crítico, por lo que podía estar seguro de que iba a abortar después de que por fin).

Se impreso:

Tema abortado? Falso

Hmmm, en verdad extraño!

Así que pensé en hacer un poco más trabajo allí, para engañar a las optimizaciones "inteligentes":

bool threadAborted = true;
try {
  try { }
  finally { /* critical code */ }
  threadAborted = AmIEvil();
}
finally {
  Console.WriteLine("Thread aborted? {0}", threadAborted);
}
Console.WriteLine("Done");

Donde AmIEviles simplemente:

[MethodImpl(MethodImplOptions.NoInlining)]
static bool AmIEvil() {
  return false;
}

Finalmente impreso:

Tema abortado? Cierto

Y ahí lo tienes. Utilizar esto en su código:

try {
  try { }
  finally { /* critical code */ }
  NoOp();
}
catch (Exception ex) {
  // ThreadAbortException is caught here now!
}

Donde NoOpes simplemente:

[MethodImpl(MethodImplOptions.NoInlining)]
static void NoOp() { }
Respondida el 03/03/2011 a las 19:02
fuente por usuario

votos
3

De hecho, puedes ejecutar código en la instrucción catch para una ThreadAbortException. El problema es que la excepción se volverá a ejecutar una vez que la ejecución abandone el bloque catch.

Si realmente desea evitar que la excepción continúe, puede llamar a Thread.ResetAbort (). Sin embargo, esto requiere confianza total y, a menos que tenga un escenario específico, es casi seguro que no es lo correcto.

ThreadAbortException

Respondida el 09/12/2008 a las 17:07
fuente por usuario

votos
2

Si llama Thread.Abort es un mal diseño ¿por qué llamar a SQL Server en un hilo que ejecuta código de usuario? Debido a esto es exactamente cómo se maneja una consulta cancelar y que provoca pesadillas.

Respondida el 18/11/2011 a las 22:23
fuente por usuario

votos
2

No creo que sea posible.

¿Por qué necesita manejar ThreadAbortException en primer lugar? Llamando Thread.Abort () es generalmente un signo de un mal diseño. Tener una variable de indicador que cuando se establece en verdadero simplemente regresará; desde la función de hilo, después de la limpieza adecuada, por supuesto.

De esta forma, no tendrá que preocuparse por la excepción.

Respondida el 09/12/2008 a las 17:22
fuente por usuario

votos
2

Lea sobre las regiones de ejecución restringida .

Específicamente, el método RuntimeHelpers.ExecuteCodeWithGuaranteedCleanup será útil aquí.

Respondida el 09/12/2008 a las 17:04
fuente por usuario

votos
0

¿Has intentado algo como ésto?

try {
    try { }
    catch (ThreadAbortException)
    {
      ThreadAbortExceptionBool = true;
    }
    finally {
        // critical logic
        if (ThreadAbortExceptionBool)
          // Whatever
    }
} 
catch(Exception ex) {
    // ThreadAbortException is not caught here, but exceptions thrown
    // from within the critical logic are
}
Respondida el 02/03/2009 a las 16:15
fuente por usuario

votos
0

Estoy de acuerdo con Arul. Calling Thread.Abort () es un signo de mal diseño.

Permítanme citar a Peter Ritchie de MSDN: Thread.Abort (el énfasis es mío):

Hay muchas razones para no usar Thread.Abort y ThreadAbortException

En ciertas plataformas (como x64 e IA64) el aborto puede ocurrir antes de que Monitor.Enter y un bloque try (incluso con lock / SyncLock), dejando el monitor huérfano. ThreadAbortException puede ocurrir en código de terceros no escrito para manejar el aborto de subprocesos. El hilo se puede cancelar mientras se procesa un bloque finally en .NET 1.x. Utiliza excepciones para la lógica de flujo de control normal. La excepción asíncrona puede interrumpir la modificación del estado o los recursos del fragmento, dejándolos dañados.

Para obtener más detalles, consulte:
http://msmvps.com/blogs/peterritchie/archive/2007/08/22/thead-abort-is-a-sign-of-a-poorly-designed-program.aspx
http: // www.bluebytesoftware.com/blog/2007/01/30/MonitorEnterThreadAbortsAndOrphanedLocks.aspx
http://blogs.msdn.com/ericlippert/archive/2007/08/17/subtleties-of-c-il-codegen.aspx

Respondida el 11/12/2008 a las 11:43
fuente por usuario

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more