¿Cómo cancelo / cancelo TPL tareas?

En un hilo, creo algún System.Threading.Task y comienzo cada tarea.

Cuando hago un .Abort() para matar el hilo, las tareas no se cancelan.

¿Cómo puedo transmitir el .Abort() a mis tareas?

No puedes. Las tareas usan subprocesos de fondo del grupo de subprocesos. Tampoco se recomienda cancelar subprocesos utilizando el método Abortar. Puede echar un vistazo a la siguiente publicación de blog que explica una forma adecuada de cancelar tareas utilizando tokens de cancelación. Aquí hay un ejemplo:

 class Program { static void Main() { var ts = new CancellationTokenSource(); CancellationToken ct = ts.Token; Task.Factory.StartNew(() => { while (true) { // do some heavy work here Thread.Sleep(100); if (ct.IsCancellationRequested) { // another thread decided to cancel Console.WriteLine("task canceled"); break; } } }, ct); // Simulate waiting 3s for the task to complete Thread.Sleep(3000); // Can't wait anymore => cancel this task ts.Cancel(); Console.ReadLine(); } } 

Anular una tarea es fácilmente posible si captura el hilo en el que se está ejecutando la tarea. Aquí hay un código de ejemplo para demostrar esto:

 void Main() { Thread thread = null; Task t = Task.Run(() => { //Capture the thread thread = Thread.CurrentThread; //Simulate work (usually from 3rd party code) Thread.Sleep(1000); //If you comment out thread.Abort(), then this will be displayed Console.WriteLine("Task finished!"); }); //This is needed in the example to avoid thread being still NULL Thread.Sleep(10); //Cancel the task by aborting the thread thread.Abort(); } 

Usé Task.Run () para mostrar el caso de uso más común para esto, utilizando la comodidad de las tareas con el código de un solo subproceso antiguo, que no utiliza la clase CancellationTokenSource para determinar si se debe cancelar o no.

Al igual que sugiere esta publicación , esto se puede hacer de la siguiente manera:

 int Foo(CancellationToken token) { Thread t = Thread.CurrentThread; using (token.Register(t.Abort)) { // compute-bound work here } } 

Aunque funciona, no se recomienda utilizar dicho enfoque. Si puede controlar el código que se ejecuta en la tarea, será mejor que proceda con el manejo adecuado de la cancelación.

Este tipo de cosas es una de las razones logísticas por las cuales Abort está en desuso. En primer lugar, no use Thread.Abort() para cancelar o detener un hilo si es posible. Abort() solo debe usarse para matar a la fuerza un hilo que no responde a solicitudes más pacíficas de detenerse de manera oportuna.

Dicho esto, debe proporcionar un indicador de cancelación compartido que establezca un hilo y espere mientras el otro hilo lo revisa periódicamente y sale con gracia. .NET 4 incluye una estructura diseñada específicamente para este propósito, el CancellationToken .

No deberías intentar hacer esto directamente. Diseñe sus tareas para que funcionen con un CancellationToken y cancélelas de esta manera.

Además, recomendaría cambiar su hilo principal para que funcione a través de un CancellationToken también. Calling Thread.Abort() es una mala idea: puede dar lugar a varios problemas que son muy difíciles de diagnosticar. En cambio, ese hilo puede usar la misma Cancelación que usan sus tareas, y el mismo CancellationTokenSource se puede utilizar para activar la cancelación de todas sus tareas y su hilo principal.

Esto conducirá a un diseño mucho más simple y seguro.

Para responder la pregunta de Prerak K sobre cómo utilizar CancellationTokens cuando no utiliza un método anónimo en Task.Factory.StartNew (), pasa el CancellationToken como parámetro al método que está comenzando con StartNew (), como se muestra en el ejemplo de MSDN aquí .

p.ej

 var tokenSource = new CancellationTokenSource(); var token = tokenSource.Token; Task.Factory.StartNew( () => DoSomeWork(1, token), token); static void DoSomeWork(int taskNum, CancellationToken ct) { // Do work here, checking and acting on ct.IsCancellationRequested where applicable, } 

Utilizo un enfoque mixto para cancelar una tarea.

  • En primer lugar, estoy tratando de cancelarlo educadamente con el uso de la cancelación .
  • Si aún se está ejecutando (por ejemplo, debido a un error del desarrollador), entonces se portará mal y lo matará usando un método de aborto de la vieja escuela.

Verifique un ejemplo a continuación:

 private CancellationTokenSource taskToken; private AutoResetEvent awaitReplyOnRequestEvent = new AutoResetEvent(false); void Main() { // Start a task which is doing nothing but sleeps 1s LaunchTaskAsync(); Thread.Sleep(100); // Stop the task StopTask(); } ///  /// Launch task in a new thread ///  void LaunchTaskAsync() { taskToken = new CancellationTokenSource(); Task.Factory.StartNew(() => { try { //Capture the thread runningTaskThread = Thread.CurrentThread; // Run the task if (taskToken.IsCancellationRequested || !awaitReplyOnRequestEvent.WaitOne(10000)) return; Console.WriteLine("Task finished!"); } catch (Exception exc) { // Handle exception } }, taskToken.Token); } ///  /// Stop running task ///  void StopTask() { // Attempt to cancel the task politely if (taskToken != null) { if (taskToken.IsCancellationRequested) return; else taskToken.Cancel(); } // Notify a waiting thread that an event has occurred if (awaitReplyOnRequestEvent != null) awaitReplyOnRequestEvent.Set(); // If 1 sec later the task is still running, kill it cruelly if (runningTaskThread != null) { try { runningTaskThread.Join(TimeSpan.FromSeconds(1)); } catch (Exception ex) { runningTaskThread.Abort(); } } } 

Puede utilizar un CancellationToken para controlar si la tarea se cancela. ¿Estás hablando de abortar antes de que se inicie (“no importa, ya lo hice”), o interrumpirlo en el medio? Si el primero, el CancellationToken puede ser útil; en este último caso, es probable que deba implementar su propio mecanismo de “rescate” y verificar en los puntos apropiados en la ejecución de la tarea si debe fallar rápidamente (aún puede utilizar el CancelToken para ayudarlo, pero es un poco más manual).

MSDN tiene un artículo sobre la cancelación de tareas: http://msdn.microsoft.com/en-us/library/dd997396.aspx

Las tareas tienen soporte de primera clase para la cancelación mediante tokens de cancelación . Cree sus tareas con tokens de cancelación y cancele las tareas a través de estos explícitamente.

La tarea se está ejecutando en el ThreadPool (al menos, si está utilizando la fábrica predeterminada), por lo que cancelar el hilo no puede afectar las tareas. Para abortar tareas, vea Cancelación de tareas en msdn.

Intenté CancellationTokenSource pero no puedo hacer esto. Y lo hice a mi manera. Y funciona.

 namespace Blokick.Provider { public class SignalRConnectProvider { public SignalRConnectProvider() { } public bool IsStopRequested { get; set; } = false; //1-)This is important and default `false`. public async Task ConnectTab() { string messageText = ""; for (int count = 1; count < 20; count++) { if (count == 1) { //Do stuff. } try { //Do stuff. } catch (Exception ex) { //Do stuff. } if (IsStopRequested) //3-)This is important. The control of the task stopping request. Must be true and in inside. { return messageText = "Task stopped."; //4-) And so return and exit the code and task. } if (Connected) { //Do stuff. } if (count == 19) { //Do stuff. } } return messageText; } } } 

Y otra clase de llamar al método:

 namespace Blokick.Views { [XamlComstacktion(XamlComstacktionOptions.Compile)] public partial class MessagePerson : ContentPage { SignalRConnectProvider signalR = new SignalRConnectProvider(); public MessagePerson() { InitializeComponent(); signalR.IsStopRequested = true; // 2-) And this. Make true if running the task and go inside if statement of the IsStopRequested property. if (signalR.ChatHubProxy != null) { signalR.Disconnect(); } LoadSignalRMessage(); } } }