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. }
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.
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.
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With