run - cancellationtoken c#
Usar CancelToken para el tiempo de espera en la tarea. (4)
OK, mis preguntas son muy simples. ¿Por qué este código no arroja TaskCancelledException
?
static void Main()
{
var v = Task.Run(() =>
{
Thread.Sleep(1000);
return 10;
}, new CancellationTokenSource(500).Token).Result;
Console.WriteLine(v); // this outputs 10 - instead of throwing error.
Console.Read();
}
Pero este funciona
static void Main()
{
var v = Task.Run(() =>
{
Thread.Sleep(1000);
return 10;
}, new CancellationToken(true).Token).Result;
Console.WriteLine(v); // this one throws
Console.Read();
}
Creo que porque no estás invocando el método ThrowIfCancellationRequested()
desde tu objeto ThrowIfCancellationRequested()
. Usted está ignorando, de esta manera, la solicitud de cancelación de la tarea.
Deberías hacer algo como esto:
void Main()
{
var ct = new CancellationTokenSource(500).Token;
var v =
Task.Run(() =>
{
Thread.Sleep(1000);
ct.ThrowIfCancellationRequested();
return 10;
}, ct).Result;
Console.WriteLine(v); //now a TaskCanceledException is thrown.
Console.Read();
}
La segunda variante de su código funciona, porque ya está inicializando un token con un estado Canceled
establecido en verdadero. De hecho, como se afirma here :
If canceled is true, both CanBeCanceled and IsCancellationRequested will be true
la cancelación ya ha sido solicitada y, a continuación, la excepción TaskCanceledException
lanzará inmediatamente, sin iniciar realmente la tarea.
Hay una diferencia en la cancelación de una tarea en ejecución y una tarea programada para ejecutarse.
Después de la llamada al método Task.Run, la tarea solo está programada y probablemente no se haya ejecutado todavía.
Cuando utiliza la familia Task.Run (..., CancelToken) de sobrecargas con soporte de cancelación, el token de cancelación se verifica cuando la tarea está a punto de ejecutarse. Si el token de cancelación tiene IsCancellationRequested establecido en verdadero en este momento, se produce una excepción del tipo TaskCanceledException.
Si la tarea ya se está ejecutando, es responsabilidad de la tarea llamar al método ThrowIfCancellationRequested o simplemente lanzar la excepción OperationCanceledException.
Según MSDN, es solo un método conveniente para lo siguiente:
si (token.IsCancellationRequested) lanza una nueva OperationCanceledException (token);
No es el tipo diferente de excepción utilizada en estos dos casos:
catch (TaskCanceledException ex)
{
// Task was canceled before running.
}
catch (OperationCanceledException ex)
{
// Task was canceled while running.
}
También tenga en cuenta que TaskCanceledException
deriva de OperationCanceledException
, por lo que solo puede tener una cláusula catch
para el tipo OperationCanceledException
:
catch (OperationCanceledException ex)
{
if (ex is TaskCanceledException)
// Task was canceled before running.
// Task was canceled while running.
}
Otra implementación usando Task.Delay con token en lugar de Thread.Sleep.
static void Main(string[] args)
{
var task = GetValueWithTimeout(1000);
Console.WriteLine(task.Result);
Console.ReadLine();
}
static async Task<int> GetValueWithTimeout(int milliseconds)
{
CancellationTokenSource cts = new CancellationTokenSource();
CancellationToken token = cts.Token;
cts.CancelAfter(milliseconds);
token.ThrowIfCancellationRequested();
var workerTask = Task.Run(async () =>
{
await Task.Delay(3500, token);
return 10;
}, token);
try
{
return await workerTask;
}
catch (OperationCanceledException )
{
return 0;
}
}
Cancelación en hilos gestionados :
La cancelación es cooperativa y no es forzada para el oyente. El oyente determina cómo terminar con gracia en respuesta a una solicitud de cancelación.
No escribió ningún código dentro de su método Task.Run
para acceder a su CancellationToken
e implementar la cancelación, por lo que ignoró la solicitud de cancelación y completó la ejecución.