Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to make Task.WaitAll() to break if any exception happened?

I want to make Task.WaitAll() to break out if any of the running tasks throws an exception, so that I don't have to wait for 60 seconds to finish. How do I achieve such behavior? If WaitAll() cannot achieve that, is there any other c# feature or workaround?

Task task1 = Task.Run(() => throw new InvalidOperationException()); Task task2 = ... ... try {     Task.WaitAll(new Task[]{task1, task2, ...}, TimeSpan.FromSeconds(60)); } catch (AggregateException) {     // If any exception thrown on any of the tasks, break out immediately instead of wait all the way to 60 seconds. } 
like image 960
user926958 Avatar asked Apr 03 '14 21:04

user926958


People also ask

Does task WaitAll block?

WhenAll we will get a task object that isn't complete. However, it will not block but will allow the program to execute. On the contrary, the Task. WaitAll method call actually blocks and waits for all other tasks to complete.

What is task WaitAll in C#?

WaitAll(Task[], Int32) Waits for all of the provided Task objects to complete execution within a specified number of milliseconds. WaitAll(Task[], CancellationToken) Waits for all of the provided Task objects to complete execution unless the wait is cancelled.

What is AggregateException in C#?

AggregateException is used to consolidate multiple failures into a single, throwable exception object. It is used extensively in the Task Parallel Library (TPL) and Parallel LINQ (PLINQ). For more information, see Exception Handling and How to: Handle Exceptions in a PLINQ Query.


1 Answers

The following should do it without altering the code of the original tasks (untested):

static bool WaitAll(Task[] tasks, int timeout, CancellationToken token) {     var cts = CancellationTokenSource.CreateLinkedTokenSource(token);      var proxyTasks = tasks.Select(task =>          task.ContinueWith(t => {             if (t.IsFaulted) cts.Cancel();             return t;          },          cts.Token,          TaskContinuationOptions.ExecuteSynchronously,          TaskScheduler.Current).Unwrap());      return Task.WaitAll(proxyTasks.ToArray(), timeout, cts.Token); } 

Note it only tracks faulted tasks (those which threw). If you need to track cancelled tasks as well, make this change:

if (t.IsFaulted || t.IsCancelled) cts.Cancel(); 

Updated, waiting on the task proxies is redundant here, as pointed out by @svick in the comments. He proposes an improved version: https://gist.github.com/svick/9992598.

like image 126
noseratio Avatar answered Oct 08 '22 20:10

noseratio