Does await* create race conditions?

As I know, in

f();
await g();
h();

there may be intermediary code execution from other calls between f() and g().

Is it true also for

f();
await* g();
h();

or is in this case the entire sequence of three statements atomic?

No.

In the first version, there definitely is a commit point and interleaving.

In the second version, there may be a commit point and interleaving.

So the second case may execute everything atomically, but you cannot predict that. If you could rely on that being the case, then you probably wouldn’t need any await in the first place.

Furthermore, if there is an error (trap) during execution of h(), then in the first case, execution is rolled back to the await. In the second case execution is rolled back to either (somewhere inside) the await* or beyond, you can’t predict it – even f() may or may not be rolled back.

Do you mean between g and h?

I meant somewhere between f and h.

@rossberg So, after

func f() { ... };
func h() { ... };
func g() async* {};
f();
await* g();
h();

may execute atomically and may not? (even though the context of g is predictable, empty in our case)

I will be unpredictable only if you have conditional awaits inside g

@qwertytrewq, yes, in that case it will be predictably atomic, but in that case the async* of course is pointless in the first place. In a case where async* is actually needed it will also be unpredictable, by construction.