How does C# decide which SyncronizationContext to check on whether an awaiter is completed
When code await
s a task, it first checks whether the task is complete. If it's already complete, then the code continues executing synchronously past the await
. Otherwise, by default await
will capture the SynchronizationContext.Current
at that time. This default behavior is prevented by using ConfigureAwait(continueOnCapturedContext: false)
.
this enable us to jump between threads when writing async methods.
True. But I don't recommend that style of code. IMO the code is more maintainable by using separate methods that each run in a specific context. Or if you don't want to use separate methods, at least split them up using delegates.
E.g., if you want to run code on a UI thread, it's cleaner to queue a method to run on that UI thread rather than have one method that is partially run on a background thread and partially run on a UI thread. This is especially true when considering error handling: if you have a try
that is partially one thread and partially another, you also have to assume the catch
/finally
blocks can run in either of those contexts.
My question is how does SynchronizationContext.Current change.
SynchronizationContext.Current
can be set by any thread, but it's usually set by whatever queueing mechanism is executing code. E.g., UI threads get their SynchronizationContext.Current
set when they enter their main loop (which includes their queue), i.e., Dispatcher.Run
for WPF or Application.Run
for WinForms.
EDIT: To be more specific, how does IAsyncStateMachine.MoveNext gets executed by different SynchronizationContext?
The SynchronizationContext
is captured by the TaskAwaiter
, and when the awaitable completes, it resumes executing the method by passing the continuation to SynchronizationContext.Post
(unless it can execute it directly).
All of this is open source, BTW.