Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Task.WaitAll and Exceptions

I have a problem with exception handling and parallel tasks.

The code shown below starts 2 tasks and waits for them to finish. My problem is, that in case a task throws an exception, the catch handler is never reached.

        List<Task> tasks = new List<Task>();         try         {                             tasks.Add(Task.Factory.StartNew(TaskMethod1));             tasks.Add(Task.Factory.StartNew(TaskMethod2));              var arr = tasks.ToArray();                             Task.WaitAll(arr);         }         catch (AggregateException e)         {             // do something         } 

However when I use the following code to wait for the tasks with a timeout, the exception is caught.

 while(!Task.WaitAll(arr,100)); 

I seem to be missing something, as the documentation for WaitAll describes my first attempt to be the correct one. Please help me in understanding why it is not working.

like image 445
thumbmunkeys Avatar asked Nov 18 '10 17:11

thumbmunkeys


People also ask

What happens if a task throws an exception?

If Bar throws an exception, it will be thrown right at the point where you call it. However, if the Task that Bar returns wraps an exception, what happens depends on your version of . NET runtime - for .

What is task WaitAll?

WaitAll(Task[], TimeSpan)Waits for all of the provided cancellable Task objects to complete execution within a specified time interval.

How do you handle exceptions in tasks?

Exceptions are propagated when you use one of the static or instance Task. Wait methods, and you handle them by enclosing the call in a try / catch statement. If a task is the parent of attached child tasks, or if you are waiting on multiple tasks, multiple exceptions could be thrown.

What is the difference between task WaitAll and task WhenAll?

The Task. WaitAll blocks the current thread until all other tasks have completed execution. The Task. WhenAll method is used to create a task that will complete if and only if all the other tasks have completed.


2 Answers

Can't reproduce this - it works fine for me:

using System; using System.Threading; using System.Threading.Tasks;  class Test {     static void Main()     {         Task t1 = Task.Factory.StartNew(() => Thread.Sleep(1000));         Task t2 = Task.Factory.StartNew(() => {             Thread.Sleep(500);             throw new Exception("Oops");         });          try         {             Task.WaitAll(t1, t2);             Console.WriteLine("All done");         }         catch (AggregateException)         {             Console.WriteLine("Something went wrong");         }     } } 

That prints "Something went wrong" just as I'd expect.

Is it possible that one of your tasks isn't finished? WaitAll really does wait for all the tasks to complete, even if some have already failed.

like image 160
Jon Skeet Avatar answered Sep 16 '22 17:09

Jon Skeet


Here's how I solved the problem, as alluded to in the comments on my answer/question (above):

The caller catches any exceptions raised by the tasks being coordinated by the barrier, and signals the other tasks with a forced cancellation:

CancellationTokenSource cancelSignal = new CancellationTokenSource(); try {     // do work     List<Task> workerTasks = new List<Task>();     foreach (Worker w in someArray)     {         workerTasks.Add(w.DoAsyncWork(cancelSignal.Token);     }     while (!Task.WaitAll(workerTasks.ToArray(), 100, cancelSignal.Token)) ;   }  catch (Exception)  {      cancelSignal.Cancel();      throw;  } 
like image 34
gap Avatar answered Sep 20 '22 17:09

gap