Destrucción de subprocesos

Para finalizar la ejecución del subproceso, normalmente se usa el modelo de cancelación cooperativa. Pero a veces no es posible detener un subproceso de forma cooperativa, ya que ejecuta código de terceros no diseñado para la cancelación cooperativa. En las aplicaciones de .NET Framework, puede usar el método Thread.Abort para finalizar forzosamente un subproceso administrado. Cuando se llama a Abort, Common Language Runtime inicia una clase ThreadAbortException en el subproceso de destino, que este último puede detectar. (Pero el entorno de ejecución de .NET Framework siempre vuelve a generar automáticamente la excepción después del bloque catch). Para obtener más información, vea Thread.Abort.

El método Thread.Abortno se admite en .NET 5 (incluido .NET Core) y versiones posteriores. Si tiene que terminar la ejecución de código de terceros de forma forzada en .NET 5 y versiones posteriores, ejecútelo en el proceso independiente y use Process.Kill.

Nota:

  • Cuando se llama a Thread.Abort para anular un subproceso distinto del actual, no se sabe qué código se ha ejecutado o no se ha podido ejecutar al iniciarse la excepción ThreadAbortException. Tampoco puede saberse a ciencia cierta el estado de la aplicación o de cualquier aplicación y estado de usuario que sea responsable de su conservación. Por ejemplo, una llamada a Thread.Abort puede evitar la ejecución de constructores estáticos o la liberación de recursos administrados o no administrados.
  • Si un subproceso ejecuta código no administrado al llamar a su método Abort, el tiempo de ejecución lo marca como ThreadState.AbortRequested. La excepción se produce cuando el subproceso vuelve al código administrado.

Una vez que se anula un subproceso, no se puede reiniciar.

El método Abort no hace que el subproceso se anule inmediatamente, porque el subproceso de destino puede detectar ThreadAbortException y ejecutar cantidades arbitrarias de código en un bloque finally. Puede llamar a Thread.Join si tiene que esperar hasta que haya finalizado el subproceso. Thread.Join es una llamada de bloqueo que no realiza ninguna devolución hasta que el subproceso se haya dejado de ejecutar realmente o hasta que haya transcurrido un intervalo de tiempo de espera opcional. El subproceso anulado podría llamar al método ResetAbort o llevar a cabo el procesamiento sin enlazar en un bloqueo finally, por lo que si no especifica un tiempo de espera, no se garantiza que la espera finalice.

Los subprocesos que esperan una llamada al método Thread.Join pueden interrumpirse con otros subprocesos que llaman a Thread.Interrupt.

Control de ThreadAbortException

Si espera que se anule el subproceso, como resultado de una llamada a Abort desde su propio código o como resultado de la descarga de un dominio de aplicación en que se ejecuta el subproceso (AppDomain.Unload usa Thread.Abort para terminar los subprocesos), el subproceso debe controlar ThreadAbortException y realizar cualquier procesamiento final en una cláusula finally, como se muestra en el código siguiente.

Try  
    ' Code that is executing when the thread is aborted.  
Catch ex As ThreadAbortException  
    ' Clean-up code can go here.  
    ' If there is no Finally clause, ThreadAbortException is  
    ' re-thrown by the system at the end of the Catch clause.
Finally  
    ' Clean-up code can go here.  
End Try  
' Do not put clean-up code here, because the exception
' is rethrown at the end of the Finally clause.  
try
{  
    // Code that is executing when the thread is aborted.  
}
catch (ThreadAbortException ex)
{  
    // Clean-up code can go here.  
    // If there is no Finally clause, ThreadAbortException is  
    // re-thrown by the system at the end of the Catch clause.
}  
// Do not put clean-up code here, because the exception
// is rethrown at the end of the Finally clause.  

El código de limpieza debe estar en la cláusula catch o en la cláusula finally, porque el sistema vuelve a generar ThreadAbortException al final de la cláusula finally o al final de la cláusula catch si no existe la cláusula finally.

Puede impedir que el sistema vuelva a generar la excepción mediante una llamada al método Thread.ResetAbort. Sin embargo, debe hacerlo solo si su propio código generó ThreadAbortException.

Vea también