2011-07-13 13 views
5

Al cancelar una tarea que tiene un tiempo de espera (antes de que el tiempo de espera haya finalizado) utilizando un token de cancelación se produce una excepción. Ejemplo:Cómo cancelar una tarea que está esperando con un tiempo de espera sin excepciones

mytask.start(); 
bool didTaskRunInTime = mytask.wait(5 mins, _cancelToken); 

Lo que significa que no puedo seguir como a continuación.

//was the task cancelled 
if (_cancelToken.IsCancelRequested) 
{ 
    // log cancel from user to file etc 
} 

if (didTaskRunInTime) 
{ 
    int taskResult = myTask.Result; 
    // log result to file 
} 
else if (!_cancelToken.IsCancelRequested) 
{ 
    // Tell user task timed out , log a message etc 
} 

Tendré que hacer todo esto en mi bloque de captura y mi código se ve desordenado. ¿Cuál es la forma correcta de hacer esto?

Respuesta

13

Puede llamar al Task.WaitAny con una matriz de solo esa tarea. Luego puede actuar sobre el estado de la tarea, sin embargo, el método retorna. Código de ejemplo:

using System; 
using System.Threading; 
using System.Threading.Tasks; 

class Test 
{ 
    static void Main() 
    { 
     Task sleeper = Task.Factory.StartNew(() => Thread.Sleep(100000)); 

     int index = Task.WaitAny(new[] { sleeper }, 
           TimeSpan.FromSeconds(0.5)); 
     Console.WriteLine(index); // Prints -1, timeout 

     var cts = new CancellationTokenSource(); 

     // Just a simple wait of getting a cancellable task 
     Task cancellable = sleeper.ContinueWith(ignored => {}, cts.Token); 

     // It doesn't matter that we cancel before the wait 
     cts.Cancel(); 

     index = Task.WaitAny(new[] { cancellable }, 
          TimeSpan.FromSeconds(0.5)); 
     Console.WriteLine(index); // 0 - task 0 has completed (ish :) 
     Console.WriteLine(cancellable.Status); // Cancelled 
    } 
} 

Tenga en cuenta que si tiene un fallo de la tarea, debe "observar" la excepción a fin de evitar que va de rotura cuando esté finalizado :)

+0

Creo que arrojará, WaitAny agregará todas las excepciones, incluso debería llamar a esperar después de waitAny (y quizás cancelar a los demás) para poder detectar sus excepciones. – eFloh

+0

gracias John. Pero waitany no toma un tiempo de espera. Tengo exportaciones de larga ejecución que requieren un tiempo de espera de manejo. – Gullu

+0

@eFloh: 'WaitAll' agrega excepciones. 'WaitAny' no. Ver el código de muestra. –

3

tratan de utilizar OperationCanceledException

try 
{   
    mytask.start(); 
    bool didTaskRunInTime = mytask.wait(5 mins, _cancelToken); 

    if (didTaskRunInTime) 
    { 
     int taskResult = myTask.Result; 
     //log result to file 
    } 
    else 
    { 
     // Tell user task timed out , log a message etc 
    } 
} 
catch (OperationCanceledException ex) 
{ 
    // log cancel from user to file et 
} 
+0

eso era lo que intentaba evitar, pero puede que no tenga otra opción. Mi razonamiento era que si alguien configuraba cancelToken y tenía la intención de cancelar, ¿por qué demonios está diseñado esto para lanzar una excepción? gracias Vlad – Gullu

+0

No hay ningún requisito para usar excepciones aquí - ver mi respuesta para un ejemplo sin una prueba/captura en absoluto. –

Cuestiones relacionadas