问题
There are tons of examples of how to wait for a thread to exit, but sometimes i need to wait just until several threads are "ready" or have reached certain milestone.
After reading: What's the proper way to wait for a .NET thread to start up?
and http://www.albahari.com/threading/
If i have understood correctly:
Wait for one Child Task to be ready:
//Main Method
var wh = new AutoResetEvent(false);
Task childTask = Task.Run(() => ChildTask(wh);
wh.WaitOne();
//Child
private void ChildTask(Barrier barrier){
//do what is needed to be done before main thread continues...
wh.Set();
}
Wait for several Childs to be ready:
//Main Method
var barrier = new Barrier(N+1);
Task childTask = Task.Run(() => ChildTask1(barrier);
Task childTask = Task.Run(() => ChildTask2(barrier);
...
Task childTask = Task.Run(() => ChildTaskN(barrier);
barrier.SignalAndWait(); //When all childs signal "ready" i will continue
OnMyEvent(); //for example, trigger an event
//Every Child
private void Child_i(Barrier barrier){
mainTask.MyEvent += MyEventHandler; //complete subscription before going any further
//do what is needed to be done before main thread continues...
barrier.SignalAndWait();
}
(Please feel free to add or suggest another good patterns)
So my question is: Is posible to use the async/await pattern to achieve the same?
Are there any advantages/disadvantages by using this new pattern?
回答1:
You can use await Task.WhenAll
or Task.WaitAll
to wait for your tasks to finish.
If you want to wait for a task to reach a certain milestone, you can split it into 2 tasks and use ContinueWith
, for example:
var task1 = Task.Run(() => Task1Part1());
task1.ContinueWith(t => Task1Part2(t.Result));
var task2 = Task.Run(() => Task2Part1());
task2.ContinueWith(t => Task2Part2(t.Result));
await Task.WhenAll(task1, task2);
回答2:
Refactoring your example, you can achieve the same result without having to use a Barrier
or AutoResetEvent
etc:
Task.WaitAll(
Task.Run(() => ChildTask1()),
Task.Run(() => ChildTask2()),
Task.Run(() => ChildTask3()));
Or slightly cleaner
Parallel.Invoke(
() => ChildTask1(),
() => ChildTask2(),
() => ChildTask3());
The issue with these methods is that they will still block the foreground thread until all the child tasks have completed. If you want to use the async await pattern then your child tasks will need to be asynchronous and the context from which you call them would also be asynchronous. The result could be something like
public async Task PerformChildTasksAsync()
{
...
await Task.WhenAll(
ChildTask1Async(),
ChildTask2Async(),
ChildTask3Async());
...
}
来源:https://stackoverflow.com/questions/32748328/wait-for-a-task-or-tasks-to-reach-certain-milestone-the-async-await-way