I took me a couple hours to track down a typo in my code that caused nasty deadlocks in TPL. So, folks, it’s been said many-many-many times. Here it is once again. Two important things on TPL.
- If you opt into using the async keyword, use it though out your code and use it as much as you can.
- if there is anything you need to wait for, then use the await key word as much as you can.
If there are any circumstances that prevent you from implementing these two rules, avoid using Tasks at all.
Said above, here is an example, in short. await Task.WhenAny(myTasks) is basically you telling the runtime “give me the a new task, signal the new task when any of my tasks complete, and in the meanwhile release the current thread”. And if you use Task.WaitAny(myTasks), then it is you telling the runtime “designate the current thread to active waiting until any of the tasks complete”, that means it does not release the current thread. Why is it so bad? Sometimes the code up the call stack will require to resume the execution on the same thread that kicked off the Task. That means if the desired thread is busy actively waiting, the Task will never finish as it will have nowhere to resume. And since the task will never finish, the waiting thread will never go on. Deadlock.