9

If I declare my event handlers as async void, will they be called synchronously or asynchronously by the .NET framework?

I.e., given the following code:

async void myButton_click(object sender, EventArgs e) {
   do stuff
   await longRunning()
   do more stuff
}

Can I be sure that the "do stuff" line will be executed on the GUI thread?

i3arnon
  • 113,022
  • 33
  • 324
  • 344
Eyvind
  • 5,221
  • 5
  • 40
  • 59

2 Answers2

15

Event handlers will be called synchronously and doesn't wait(await) till the event handler completes, but waits till the event handler returns.

If previous sentence was confusing enough, I'll try to explain it clear. Asynchronous methods completes when all the await points are executed and the end of the method body has reached or any return statement is executed(Ignoring the exception). But asynchronous method returns as soon as you hit the first await statement for the Task which is not yet completed. In other words asynchronous method can return several times but can complete only once.

So now we know when does a asynchronous method completes and returns. Event handler will assume your method has completed as soon as it returns not when it actually completes.

As soon as your event handler reaches first await statement, it will return, if there are more methods attached to same event handler, it will continue executing them without waiting for the asynchronous method to complete.

Yes, do stuff will be executed in UI thread if the UI thread fires the event and yes do more stuff will also be executed in UI thread as long as longRunning().ConfigureAwait(false) isn't called.

Sriram Sakthivel
  • 72,067
  • 7
  • 111
  • 189
  • 2
    Thanks, your first sentence was enough for me :) – Eyvind Dec 01 '14 at 12:54
  • @Eyvind Not all people are smart. That's why I explained in another words assuming it will help future readers :) – Sriram Sakthivel Dec 01 '14 at 12:57
  • 1
    I think the wording in your last paragraph is slightly misleading; `do more stuff` will execute in the UI thread even if there's a call to `ConfigureAwait(false)` within `longRunning`. – Stephen Cleary Dec 01 '14 at 13:33
  • @StephenCleary Removed that part. I guess I'm missing something here, need to work on that part. Thanks. – Sriram Sakthivel Dec 01 '14 at 13:36
  • @StephenCleary So the scope of `ConfigureAwait(false)` is only within the state machine in which the `ConfigureAwait` was called am I right? – Sriram Sakthivel Dec 01 '14 at 13:43
  • 2
    @SriramSakthivel: Yes. I think of it like this: each method is independent; it captures its own context at `await` and resumes in that context. So if a method further down the call stack doesn't resume in its context, that doesn't matter. – Stephen Cleary Dec 01 '14 at 13:51
  • Thanks @StephenCleary, that cleared up another somewhat confusing point for me! – Eyvind Dec 02 '14 at 07:33
6

They will be invoked just as any other non-async-await method is invoked:

Click(this, EventArgs.Empty);

Because this specific event handler is an async method the call would run synchronously until an await is reached and the rest would be a continuation. That means that do stuff is executed synchronously on the GUI thread. The caller then moves on without the knowledge that the async operation hasn't completed yet.

do more stuff would also be executed on the GUI thread, but for a different reason. The SynchronizationContext in a GUI environment makes sure the continuations would be posted to the single GUI thread, unless you explicitly tell it not to with await longRunning().ConfigureAwait(false)

i3arnon
  • 113,022
  • 33
  • 324
  • 344