Reputation: 9
I understand .ConfigureAwait(false)
means the continuation does not have to be on the same thread as when entered.
So I wonder what Synchronization Context will I get back in someUIButton_click.
static async void someUIButton_click()
{
await T1();
// Am I sur to be on the UI thread ?
}
static async Task T1() => await doSomethingAsync().ConfigureAwait(false)
Context : C#, winforms, .Net 4.7
Upvotes: 0
Views: 1695
Reputation: 81483
Every thread has a context associated with it, this is also known as the Current Context and these contexts can be shared across threads. The ExecutionContext
contains relevant metadata of the current environment or context in which the program is in execution.
The SynchronizationContext
represents an abstraction that defines the location where your application's code is executed. SynchronizationContext
is a representation of the current environment that our code is running in, it provides a way to queue a unit of work to a context.
The SynchronizationContext
has a context associated with it and in different situations and different frameworks may represent different things. For example
WindowsFormsSynchronizationContext
DispatcherSynchronizationContext
SynchronizationContext
AspNetSynchronizationContext
Async/await is just compiler magic to make it easier to compose asynchronous stuff (it does not make your code run asynchronously), all it does when it sees an await
is splits your method up into a State Machine and when the thing you are awaiting finishes executing, the state machine is resumed and your code continues running. Resuming execution is called the continuation.
A feature of the await
keyword is that it captures the current SynchronizationContext
before it runs the asynchronous operation, then it will post the continuation to that SynchronizationContext
, meaning if you are on the UI Thread when you await
, once it has finished running then your code will continue execution on the UI Thread (which is called Offloading)
All ConfigureAwait(false)
does is configures the task so that continuation after the await
does not have to be run in the caller context. This can have several benefits, one of them is a small performance gain, and more controversially stopping deadlocks in certain situations.
Every time you call await
it creates a State Machine to do the wonders of the Async Await Pattern and sets up a continuation.
Just because you have ConfigureAwait
set to false
nested in another await
(State Machine) doesn't change the original call which is set to continue on the calling Synchronization Context (if applicable).
Side note : someUIButton_click
is running unobserved and you should have appropriate error checking
So that means that I can do whatever I want in
T1
as long it does not interacts with some UI components
You are "seemingly" free to access UI components from both someUIButton_click
and T1
however, with the exception that after the await
in T1
you have configured the task so that the continuation does not need to return to the calling context. Accessing the a UI
component here will likely cause you problems.
So what about after the await
in someUIButton_click
?
Well in that case, task has (by default) captured the current context (presumably your UI thread), and the continuation will continue on that context. Each nested await is a different case, and the calling await
(state machine) gets to choose which context it continues on
Upvotes: 4