¿Cómo puedo abortar / cancelar Tareas de TPL?
En un hilo, creo un poco de System.Threading.Task
y comienzo cada tarea.
Cuando hago un .Abort()
para matar el hilo, las tareas no se abortan.
¿Cómo puedo transmitir el .Abort()
a mis tareas ?
11 answers
No se puede. Las tareas usan subprocesos en segundo plano del grupo de subprocesos. Tampoco se recomienda cancelar hilos usando el método Abortar. Usted puede echar un vistazo a la siguiente entrada de blog que explica una forma adecuada de cancelar tareas utilizando tokens de cancelación. He aquí 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();
}
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-01-24 16:11:09
Abortar 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é Tarea.Run () para mostrar el caso de uso más común para esto, usando la comodidad de las Tareas con código antiguo de subproceso único, que no usa la clase CancellationTokenSource para determinar si debe cancelarse o no.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-02-06 21:19:03
Como este post sugiere, 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 este enfoque. Si puede controlar el código que se ejecuta en la tarea, será mejor que vaya con el manejo adecuado de la cancelación.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-10-11 06:26:20
Este tipo de cosas es una de las razones logísticas por las que Abort
está en desuso. En primer lugar, no use Thread.Abort()
para cancelar o detener un hilo si es posible. Abort()
sólo debería utilizarse para matar por la fuerza un hilo que no responde a peticiones más pacíficas de detenerse de manera oportuna.
Dicho esto, es necesario proporcionar un indicador de cancelación compartida que un hilo establece y espera mientras que el otro hilo comprueba periódicamente y sale con gracia. . NET 4 incluye una estructura diseñada específicamente para este propósito, el CancellationToken
.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-01-24 15:48:23
Usted no debe tratar de 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 funcionar a través de un CancellationToken también. Llamar a Thread.Abort()
es una mala idea - puede llevar a varios problemas que son muy difíciles de diagnosticar. En su lugar, ese hilo puede usar la misma Cancelación que tus tareas usan-y la misma CancellationTokenSource
se puede usar para activar la cancelación de todas tus tareas y tu hilo principal.
Esto conducirá a un diseño mucho más simple y seguro.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-01-24 15:46:53
Para responder a la pregunta de Prerak K sobre cómo usar CancellationTokens cuando no se usa un método anónimo en Task.Fábrica.StartNew(), pasas el CancellationToken como un parámetro en el método con el que estás comenzando StartNew (), como se muestra en el ejemplo de MSDN aquí.
Por ejemplo
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,
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-10-14 13:49:39
Utilizo un enfoque mixto para cancelar una tarea.
- En primer lugar, estoy tratando de cancelarlo cortésmente con el uso de la Cancelación.
- Si todavía se está ejecutando (por ejemplo, debido a un error del desarrollador), entonces portarse mal y matarlo usando un método de la vieja escuela Abortar.
Checkout 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();
}
/// <summary>
/// Launch task in a new thread
/// </summary>
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);
}
/// <summary>
/// Stop running task
/// </summary>
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();
}
}
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-08-06 04:06:37
Puede usar un CancellationToken
para controlar si la tarea se cancela. ¿Estás hablando de abortarlo antes de que comience ("nevermind, ya hice esto"), o realmente interrumpirlo en el medio? Si el primero, el CancellationToken
puede ser útil; si el segundo, probablemente necesitará 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 usar el CancellationToken para ayudarlo, pero es un poco más manual).
MSDN tiene un artículo sobre cancelar tareas: http://msdn.microsoft.com/en-us/library/dd997396.aspx
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-01-24 15:45:30
Las tareas tienen soporte de primera clase para la cancelación a través de tokens de cancelación. Cree sus tareas con tokens de cancelación y cancele las tareas a través de estos explícitamente.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-01-24 15:44:54
La tarea se está ejecutando en el ThreadPool (al menos, si está utilizando la fábrica predeterminada), por lo que abortar el subproceso no puede afectar a las tareas. Para abortar tareas, consulte Cancelación de tareas en msdn.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-01-24 15:46:46
Lo 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<string> 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 del método que llama:
namespace Blokick.Views
{
[XamlCompilation(XamlCompilationOptions.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();
}
}
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-11-30 20:59:04