简体   繁体   中英

Stop execution if one of the tasks is faulted

I have a question on TPL tasks. I have some tasks that are a "Show Stoppers", once one of them is faulted i dont want the method to continue running but give an exception and exit. I tried using TaskContinuationOptions, something like this:

var res = Task.Factory.ContinueWhenAny(
            new[] { task1, task2, task3},
                    task =>
                    {
                        throw task.Exception.Flatten();
                    },
                    CancellationToken.None,
                    TaskContinuationOptions.OnlyOnFaulted,
                    this.taskScheduler);

var res1 = Task.Factory.ContinueWhenAll(
                    new[] { task1, task2, task3},
                    tasks =>
                    {
                        // DO SOME CODE
                    },
                    CancellationToken.None,
                    TaskContinuationOptions.NotOnFaulted,
                    this.taskScheduler);

return Task.WhenAny(res, res1).Unwrap();

But unfortunately there is a limitation filtering on a TaskContinuationOptions when continuing on more that a one task. What is the solution to this?

You can implement a loop which checks if the tasks are faulted as they finish. If one of them faults, you could throw and exit the method:

List<Task> tasks = new List<Task> {task1, task2, task3}; // Show stopping tasks.
while (tasks.Count > 0)
{
    var finishedTask = await Task.WhenAny(tasks);
    tasks.Remove(finishedTask);

    if (finishedTask.Status == TaskStatus.Faulted)
    {
        // Throw and exit the method.
    }
}

// Continuation code goes here.

Note this will not cancel the other ongoing tasks. You could implement a cancelling mechanism if needed using CancellationToken and explicitly cancel the remaining tasks. Your tasks will need to monitor the cancellation token to see if there was a request for cancellation, either by looking at CancellationToken.IsCancellationRequested property or by using the CancellationToken.ThrowIfCancellationRequested method:

var cts = new CancellationTokenSource();

     // Generate some tasks for this example.
var task1 = Task.Run(async () => await Task.Delay(1000, cts.Token), cts.Token);
var task2 = Task.Run(async () => await Task.Delay(2000, cts.Token), cts.Token);
var task3 = Task.Run(async () => await Task.Delay(3000, cts.Token), cts.Token);

List<Task> tasks = new List<Task> {task1, task2, task3};
while (tasks.Count > 0)
{
    var finishedTask = await Task.WhenAny(tasks);
    tasks.Remove(finishedTask);

    if (finishedTask.Status == TaskStatus.Faulted)
    {
        cts.Cancel();
        // Throw and exit the method.
    }
}

You can use a CancellationTokenSource and run all your tasks with this cancellation token , so if the token is cancelled then rest of tasks will be cancelled as well

      var cs = new CancellationTokenSource();
      var options = new ParallelOptions { CancellationToken = cs.Token };
      var array = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
      try
      {
          Parallel.ForEach(array, options, (index) =>
          {
              CallCustomMethod(cs, index);
          });
      }
      catch (OperationCanceledException ex)
      { 
      }

     void CallCustomMethod(CancellationTokenSource cs, int index)  
     {   
        try
        {
            if (cs.IsCancellationRequested)
            {
                return;
            }
            if (index == 4)
            {
                throw new Exception("Cancel");
            }

            Console.WriteLine(index);
        }
        catch
        {
            cs.Cancel();
        }
    }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM