I can't figure out why Task.Delay(1).Wait() does not block the UI thread when called directly, but does when wrapped inside another Task that is then syncrhonously waited on.
Take for example this simple WPF window:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
DoesNotDeadlock().Wait(); // <-- continues just fine
CausesDeadlock().Wait(); // <-- deadlocks
}
private Task DoesNotDeadlock()
=> Task.Delay(1);
private async Task CausesDeadlock()
=> await Task.Delay(1);
}
Why is the behavior different if we wait for the Delay Task directly vs if we wait for the Task that wraps it?
.Wait()anyway so I hope this is not a quest to figure out how to safely use it. You shouldn't,.Wait()and.Resultshould be reserved for task-related libraries and only in those cases.awaitfor a Windows program does the equivalent of callingControl.Invoke()when theawaitis reached inCausesDeadlock(). But because your window is blocked in theCausesDeadlock().Wait()it is unable to process the message sent byControl.Invoke()because the message processing loop is not active, and therefore it locks up.Task DoesNotDeadlockexecutes completely synchronously, with noasyncmachinery. Thus, no potential for deadlock.Task CausesDeadlockusesasyncmachinery because the innerawaithas an incompleteTaskto return. Thus, it deadlocks as per blog.stephencleary.com/2012/07/dont-block-on-async-code.html.awaitoperator that causes it to happen (and only when needed). By creating, returning and storing an instance ofTask, you invoke no async machinery yet. It's only after youawaitsomething the async part will happen, provided the Task in question is not already complete. Thus,DoesNotDeadlockis completely synchronous, andCausesDeadlockis not because it has an incompleteawaitinside it.