Let me just post a simple example:
private void MyMethod()
{
Task task = MyAsyncMethod();
task.Wait();
}
private async Task MyAsyncMethod()
{
//Code before await
await MyOtherAsyncMethod();
//Code after await
}
Let's say I run the above code in a single threaded app -like a console app-. I'm having a difficult time understanding how the code //Code after await
would be able to run.
I understand that when I hit the await
keyword in MyAsyncMethod()
control goes back to MyMethod()
, but then I'm locking the thread with task.Wait()
. If the thread is locked, how can //Code after await
ever run if the thread that is supposed to take it is locked?
Does a new thread get created to run //Code after await
? Or does the main thread magically steps out of task.Wait()
to run //Code after await
?
I'm not sure how this is supposed to work?
Code as posted will "Deadlock" in Winform App if called from main thread because you're blocking the main thread with the Wait()
.
But in console app this works. but how?
Answer is hidden in the SynchronizationContext.Current
. await
captures the "SynchronizationContext" and when the task is completed it will continue in the same "SynchronizationContext".
In winform app SynchronizationContext.Current
will be set to WindowsFormsSynchronizationContext
which will post to the call to "Message loop", but who is going to process that? out main thread is waiting in Wait()
.
In console app SynchronizationContext.Current
will not be set by default so it will be null
when no "SynchronizationContext" available for await to capture so it will schedule the continuation to ThreadPool
(TaskScheduler.Default which is ThreadpoolTaskScheduler) and so the code after await works(through threadpool thread).
Aforementioned capturing behavior can be controlled using Task.ConfigureAwait(false);
which will prevent winform app from deadlocking but code after await
no longer runs in UI thread.