Why does a bool "flag" get generated for the async/await state machine?
Asked Answered
K

1

11

If you compile the following code:

private async Task<int> M()
{
    return await Task.FromResult(0);
}

And then decompile it (I used dotPeek) and examine the all-important MoveNext method, you will see a bool variable declared near the beginning; dotPeek chose "flag" for me.

bool flag = true;

In this case, you will see one subsequent consumer of that variable, in the default case statement after initiating the first async call:

if (!awaiter.IsCompleted)
{
    this.\u003C\u003E1__state = 0;
    this.\u003C\u003Eu__\u0024awaiter11 = awaiter;
    this.\u003C\u003Et__builder.AwaitUnsafeOnCompleted<TaskAwaiter<int>, Program.\u003CP\u003Ed__10>(ref awaiter, ref this);
    flag = false;
    return;
}

I've tried half a dozen more complicated examples than my initial one, and they are consistent in only assigning to this variable before exiting the method. So in other words, in all the cases I've tried so far, this variable is not only never consumed, but is only given a non-initial value immediately before returning from the method -- a point in time where the assignment is definitionally useless.

As background, I am enjoying the process of trying to implement async/await in Javascript via a C# -> JS cross-compiler. I'm trying to understand in what situation I need to consider the utility of this flag. At face, it seems spurious and therefore I should ignore it. However, I'd like to understand why the C# compiler introduces this variable -- I suspect there are more complicated expressions that consume this variable in a useful way.

To put is succinctly: Why does the C# compiler generate this flag variable?

Kelda answered 13/3, 2014 at 5:7 Comment(3)
Wrap your await statement in a try-finally block and set some variable inside the finally block. I don't fully understand what the IL logic is doing but I just did a quick look and it looks like it uses that flag variable to check when to execute code inside the finally block.Defy
@IlianPinzon, I fully admire your modesty, but SO works better if you post such an excellent response as an answer. You are absolutely correct and have answered my question perfectly. :)Kelda
@IlianPinzon has the correct answer. This is explained in more detail in one of Jon Skeet's eduasync posts. Since you're writing a cross-compiler, I strongly recommend reading that whole series.Metaphysics
I
1

The following comment posted under the question describes its use:

Wrap your await statement in a try-finally block and set some variable inside the finally block. I don't fully understand what the IL logic is doing but I just did a quick look and it looks like it uses that flag variable to check when to execute code inside the finally block.

–Ilian Pinzon

Also Stephen Cleary adds some useful information for the interested reader. He recommends this blog series and in particular this blog post.

@IlianPinzon has the correct answer. This is explained in more detail in one of Jon Skeet's eduasync posts. Since you're writing a cross-compiler, I strongly recommend reading that whole series.

–Stephen Cleary

Impropriety answered 13/3, 2014 at 5:7 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.