-1

Consider this simple async method:

private static async Task<int> foo()
{
    await Task.Delay(1500);
    return 1;
}

If I do the following in a WinForm application, as I expect, it deadlocks

private void Form1_Load(object sender, EventArgs e)
{
    var fooTask = foo();
    fooTask.Wait();
}

However, if I do the same in a ConsoleApplication it works (doesn't deadlock)

static void Main(string[] args)
{
    var fooTask = foo();
    fooTask.Wait();
}

Why this happens? Shouldn't the Task be unable to continue because the context thread is "blocked"?

Matteo Umili
  • 3,412
  • 1
  • 19
  • 31
  • 1
    context != thread. See [This Article](https://msdn.microsoft.com/magazine/gg598924.aspx) for lots of details. – Damien_The_Unbeliever Jan 20 '17 at 14:33
  • You also may have more info in the answer of this question: http://stackoverflow.com/questions/13140523/await-vs-task-wait-deadlock and the blog post mentionned in it. – Niitaku Jan 20 '17 at 14:34
  • @Damien_The_Unbeliever I think that I still don't understand the concept of context, but is it correct if I say that basically a `SynchronizationContext` decides which `Thread` will continue a suspended `work unit`? – Matteo Umili Jan 20 '17 at 14:57
  • @Niitaku I think that linked question is more about the difference between `Wait`/`await` – Matteo Umili Jan 20 '17 at 14:58
  • 1
    @MatteoUmili That's why I didn't flag as duplicate. I was commenting to target [this blog post](http://blog.stephencleary.com/2012/07/dont-block-on-async-code.html) mentioned in the answer that explain why a `Task.Wait` can deadlock in a SynchronizationContext (scroll to _"What Causes the Deadlock"_ part). – Niitaku Jan 20 '17 at 15:03
  • Could someone please explain me the downvotes? – Matteo Umili Jan 20 '17 at 15:20
  • 1
    The context has to schedule the work to happen somewhere. Some contexts nominate one thread as being special and arrange for all work to happen on that thread. But other contexts could do whatever they want to do. – Damien_The_Unbeliever Jan 20 '17 at 15:27

1 Answers1

3

Because WinForms applications have a SynchronizationContext. That means, whenever you await an asynchronous operation, the operation will be continued (by default) on the same SynchronizationContext.

You can change this behavior by calling ConfigureAwait(false) which will not capture the SynchronizationContext.

In your case, this SynchronizationContext is for the UI thread. Thus, when you execute

await Task.Delay(1500)

The continuation code will be executed on the UI thread. But in the same time, the UI thread is blocked because of the

fooTask.Wait()

ConsoleApplications however don't have SynchronizationContext, thus the continuation of asynchronous operations might be executed on different threads.

m1o2
  • 1,549
  • 2
  • 17
  • 27