Task.WaitAll method can throw an AggregateException, but Task.WaitAny method does not.
Questions:
- I do not understand for what purpose the developers of the framework did this?
- How to catch an exception from a task using
Task.WaitAnymethod?
Example:
using System;
using System.Threading.Tasks;
namespace ConsoleApp1
{
class Program
{
static void Main(string[] args)
{
void MyMethodForDivideByZeroException()
{
int a = 1;
a = a / 0;
}
void MyMethodForIndexOutOfRangeException()
{
int[] MyArrayForInt = new int[2] { 1, 2 };
Console.WriteLine(MyArrayForInt[2]);
}
Task MyTask22 = new Task(MyMethodForDivideByZeroException);
Task MyTask23 = new Task(MyMethodForIndexOutOfRangeException);
MyTask22.Start();
MyTask23.Start();
Task.WaitAny(MyTask22, MyTask23); //No exceptions
//Task.WaitAll(MyTask22, MyTask23); //AggregateException
Console.WriteLine(MyTask22.Status);
Console.WriteLine(MyTask23.Status);
}
}
}
CodePudding user response:
WaitAny() waits for any one of the tasks to complete (successfuly or otherwise).
When one does, with an exception, the exception is not propagated (thrown).
WaitAll() waits for all of the tasks to complete.
As they both throw an exception, these are aggregated into an AggregateException.
You can check for errors like this:
var tasks = new[] { MyTask22, MyTask23 };
int taskIndex = Task.WaitAny(tasks); //No exceptions
if (taskIndex >= 0)
{
throw tasks[taskIndex].Exception;
}
More useful information here:
- https://docs.microsoft.com/en-us/dotnet/standard/parallel-programming/exception-handling-task-parallel-library
- https://blog.stephencleary.com/2014/10/a-tour-of-task-part-5-wait.html
CodePudding user response:
The job of the Task.WaitAny method is to inform you that a task has completed, not that a task has completed successfully.
I'll answer your questions in reverse order:
- How to catch an exception from a task using
Task.WaitAnymethod?
You probably ask how to throw the exception of a completed task that has failed. The simplest way is probably just to Wait the task:
var tasks = new Task[] { MyTask22, MyTask23 };
int completedTaskIndex = Task.WaitAny(tasks);
tasks[completedTaskIndex].Wait();
- I do not understand for what purpose the developers of the framework did this?
Because otherwise the method would not be able to do its intended job. You won't be able to use this method in order to be informed about the completion of a task. Instead of getting the index of the completed task, you would get a useless and expensive exception. You could catch this exception, but you would still don't know which of the tasks is the one that caused the exception.
