michael
michael

Reputation: 110650

How to use Task.WaitAll to wait both tasks

I have the following code which calls 2 async methods and wait for results:

private Task FirstTaskAsync() {
...
}
private Task SecondTaskAsync() {
...
}

private async void Caller() {
   await FirstTaskAsync();
   await SecondTaskAsync();
}

Problem is it now executes and waits for each task sequentially. I want to change it to Task.WaitAll(). Here is my change:

private async void Caller() {
   var first = FirstTaskAsync();
   var second = SecondTaskAsync();

   Task.WaitAll(first, second);
}

But when I test it, Task.WaitAll() never returns. Can you please tell me what is missing?

Upvotes: 0

Views: 1070

Answers (2)

Scott Chamberlain
Scott Chamberlain

Reputation: 127603

First of all, you should never do async void unless you are doing a event handler (which I doubt you are), if you did async Task it makes it more obvious what your problem is.

private async Task Caller() {
   await FirstTaskAsync();
   await SecondTaskAsync();
}

//This still will not work...
private async Task Caller() {
   var first = FirstTaskAsync();
   var second = SecondTaskAsync();

   Task.WaitAll(first, second);
}

Task.WaitAll returns void and you never use await in the second method, so you are executing the code synchronously and blocking on the SynchronizationContext which will cause you to get deadlocks like you are seeing.

The correct solution would be not to block but instead use Task.WhenAll which returns a Task itself which allows you to drop the async keyword and just return the result

private Task Caller() {
   var first = FirstTaskAsync();
   var second = SecondTaskAsync();

   return Task.WhenAll(first, second);
}

However, if Caller() really is a event handler you can also do async void and just await the result.

private async void Caller() { //This should only be done if this is a event handler.
   var first = FirstTaskAsync();
   var second = SecondTaskAsync();

   await Task.WhenAll(first, second);
}

Upvotes: 5

failedprogramming
failedprogramming

Reputation: 2522

Would this work for you?

private async void Caller() 
{
    Task[] tasks = new Task[2];
    tasks[0] = FirstTaskAsync();
    tasks[1] = SecondTaskAsync();

    await Task.WhenAll(tasks);
}

Upvotes: 0

Related Questions