Reputation: 1005
I have List tasks, these tasks do some irrelevant work. What I need is to show message box in case all the tasks did their work correctly. I tried few ways, but nothing worked properly for me. Simplest way could be use
Task continuation = Tasks.WhenAll(tasks);
continuation.ContinueWith(obj => {
show messagebox
});
but ContinueWith still runs for all tasks, not just for continuation task. I tried to set cancellation token or to use sign, but tasks run at same time, so it isn't working.
I will be grateful for any help.
Upvotes: 2
Views: 6250
Reputation: 30512
There is a difference between using Tasks in a non-async function and using it in an async function.
The short and easy answer to your question is not to use Task.WhenAll, but to use Task.WaitAll. This function returns as soon as all Tasks are finished. After that you can continue with the next statement, show the message box
private void OnButton1_clicked(object sender, ...)
{
Task task1 = StartTask1(...);
Task task2 = StartTask2(...);
// do other things, after a while wait until all tasks are finished
Task.WaitAll(new Task[] {task1, task2};
MessageBox.Show(...)
}
Problem: your UI is not responsive while waiting for the tasks to finished
An easy method to keep your UI responsive is using async - await. Async-await keeps your program responsive, because whenever if the procedure has to wait for something lengthy to finish, control is given back to your main program which has time to do other things.
The nice thing about async-await is that the code still looks sequential. You don't have to use ContinueWith in the meaning of "when this task is finished do this other task".
All you have to do to be able to use async-await is declare your event handler async. In the eventhandler you can call any other async function. Whenever you need the result of the called function you await for the task.
Your code would look like follows:
private async void OnButton1_clicked(object sender, ...)
{
Task task1 = StartTask1(...);
Task task2 = StartTask2(...);
// while the tasks are being performed do other things,
// after a while wait until all tasks are finished
await Task.WhenAll(new Task[] {task1, task2};
MessageBox.Show(...)
}
This code makes sure that while waiting your UI is responsive. The only things I did to do this were:
To be able to use async-await keep the following in mind:
<Tresult
> instead of TResult<TResult
> is TresultEric Lippert (thanx Eric!) explained async-await as follows in Stackoverflow - async/await - Is this understanding correct?
Suppose for breakfast you have to toast bread and cook eggs. There are several scenarios for it:
Upvotes: 2
Reputation: 149656
ContinueWith still runs for all tasks, not just for continuation task.
That's incorrect. ContinueWith
will run once, when all tasks finish execution. You can simulate this quite easily:
var tasks = new[] { Task.Delay(1000), Task.Delay(2000), Task.Delay(500) };
Task.WhenAll(tasks).ContinueWith(x => Console.WriteLine("Finished"));
Console.Read();
You will only see "Finished" printed once.
If you can, I'd most certainly prefer to use await
instead of attaching a continuation:
public async Task FooAsync()
{
var tasks = new[] { Task.Delay(1000), Task.Delay(2000), Task.Delay(500) };
await Task.WhenAll(tasks);
Console.WriteLine("Done").
}
Upvotes: 3