Live data from Hacker News

Looking at Unity made me understand the point of C++ coroutines

mropert.github.io

101–110 of 190 posts

Re: Looking at Unity made me understand the point of C++ coroutines

#101

Coroutines is just a way to write continuations in an imperative style and with more overhead. I never understood the value. Just use lambdas/callbacks.

I'll take the bait. Here's a coroutine waitFrames(5); // wait 5 frames fireProjectile(); waitFrames(15); turnLeft(-30/*deg*/, 120); // turn left over 120 frames waitFrames(10); fireProjectile(); // spin and shoot for (i of range(0, 360, 60)) { turnRight(60, 90); // turn 60 degrees over 90 frames fireProjectile(); } 10 lines and I get behavior over time. What would your non-coroutine solution look like?

Given a coroutine body

``` int f() { a; co_yield r; b; co_return r2; } ```

this transforms into

``` auto f(auto then) { a; return then(r, [&]() { b; return then(r2); }); }; ```

You can easily extend this to arbitrarily complex statements. The main thing is that obviously, you have to worry about the capture lifetime yourself (coroutines allocate a frame separate from the stack), and the syntax causes nesting for every statement (but you can avoid that using operator overloading, like C++26/29 does for executors)

Re: Looking at Unity made me understand the point of C++ coroutines

#102
post #57
post #41

Earlier quoted context omitted.

One annoying piece of Unity's CoreCLR plan is there is no plan to upgrade IL2CPP (Unity's AOT compiler) to use a better garbage collector. It will continue to use Boehm GC, which is so much worse for games.

Why wouldn't they use the GC that comes with the dotnet AOT runtime?

They just haven't announced any plans to do so yet. They might one day.

They will not be using .NET AOT probably ever though. Unity's AOT basically supports full C# (reflection etc) while .NET opted to restrict it and lean more on generated code.

Re: Looking at Unity made me understand the point of C++ coroutines

#103

Not an expert in game development, but I'd say the issue with C++ coroutines (and 'colored' async functions in general) is that the whole call stack must be written to support that. From a practical perspective, that must in turn be backed by a multithreaded event loop to be useful, which is very difficult to write performantly and correctly. Hence, most people end up using coroutines with something like boost::asio,…

> but I'd say the issue with C++ coroutines (and 'colored' async functions in general) is that the whole call stack must be written to support that.

You can call a function that makes use of coroutines without worrying about it. That's the core intent of the design.

That is, if you currently use some blocking socket library, we could replace the implementation of that with coroutine based sockets, and everything should still work without other code changes.

Re: Looking at Unity made me understand the point of C++ coroutines

#104
post #9

Simon Tatham, author of Putty, has quite a detailed blog post [0] on using the C++20's coroutine system. And yep, it's a lot to do on your own, C++26 really ought to give us some pre-built templates/patterns/scaffolds. [0] https://web.archive.org/web/20260105235513/https://www.chiar...

People love to complain about Rust async-await being too complicated, but somehow C++ manages to be even worse. C++ never disappoints!

[deleted]

Re: Looking at Unity made me understand the point of C++ coroutines

#105
post #15

Earlier quoted context omitted.

> You can roll stackful coroutines in C++ (or C) with 50-ish lines of Assembly I'm not normally keen to "well actually" people with the C standard, but .. if you're writing in assembly, you're not writing in C. And the obvious consequence is that it stops being portable. Minicoro only supports three architectures. Granted, those are the three most popular ones, but other architectures exist. (just double checked and…

> I'm not normally keen to "well actually" people with the C standard, but .. if you're writing in assembly, you're not writing in C. These days on Linux/BSD/Solaris/macOS you can use makecontext()/swapcontext() from ucontext.h and it will turn out roughly the same performance on important architectures as what everyone used to do with custom assembly. And you already have fiber functions as part of the Windows API t…

Unfortunately swap context requires saving and restoring the signal mask, which, at least on Linux, requires a syscall so it is going to be at least a hundred times slower than an hand rolled implementation.

Also, although not likely to be removed anytime soon from existing systems, POSIX has declared the context API obsolescent a while ago (it might actually no longer be part of the standard).

Re: Looking at Unity made me understand the point of C++ coroutines

#106
post #99
post #9

Simon Tatham, author of Putty, has quite a detailed blog post [0] on using the C++20's coroutine system. And yep, it's a lot to do on your own, C++26 really ought to give us some pre-built templates/patterns/scaffolds. [0] https://web.archive.org/web/20260105235513/https://www.chiar...

See also C++ coroutines resources (posts, research, software, talks): https://gist.github.com/MattPD/9b55db49537a90545a90447392ad3...

For a layperson it's clear that it's either "Writings" and "Talks", or "Readings" and "'Listenings", but CPP profeciency is in an inverse relation with being apt in taxonomy, it looks like.

Thanks for the list.

Re: Looking at Unity made me understand the point of C++ coroutines

#107
post #87
post #15

Earlier quoted context omitted.

> You can roll stackful coroutines in C++ (or C) with 50-ish lines of Assembly I'm not normally keen to "well actually" people with the C standard, but .. if you're writing in assembly, you're not writing in C. And the obvious consequence is that it stops being portable. Minicoro only supports three architectures. Granted, those are the three most popular ones, but other architectures exist. (just double checked and…

Looking at the repo, it falls back to Windows fibers on Windows/ARM. If you'd like a coroutine with more backends, I'm a fan of libco: https://github.com/higan-emu/libco/ which has assembly backends for x86, amd64, ppc, ppc-64, arm, and arm64 (and falls back to setjmp on POSIX platforms and fibers on Windows). Obviously the real solution would be for the C or C++ committees to add stackful coroutines to the standard,…

A proposal to add stackfull coroutines has been around forever and gets updated at every single mailing. Unfortunately the authors don't really have backing from any major company.

Re: Looking at Unity made me understand the point of C++ coroutines

#108
post #100

You can roll stackful coroutines in C++ (or C) with 50-ish lines of Assembly. It's a matter of saving a few registers and switching the stack pointer, minicoro [1] is a pretty good C library that does it. I like this model a lot more than C++20 coroutines: 1. C++20 coros are stackless, in the general case every async "function call" heap allocates. 2. If you do your own stackful coroutines, every function can suspend…

> every async "function call" heap allocates. > require the STL That it has to heap-allocate if non-inlined is a misconception. This is only the default behavior. One can define: void *operator new(size_t sz, Foo &foo) in the coro's promise type, and this: - removes the implicitly-defined operator new - forces the coro's signature to be CoroType f(Foo &foo), and forwards arguments to the "operator new" one defined Th…

A stackful coroutine implementation has to save exactly the same registers that a stackless one has to: the live ones at the suspension point.

A pure library implementation that uses on normal function call semantics obviously needs to conservatively save at least all callee-save registers, but that's not the only possible implementation. An implementation with compiler help should be able to do significantly better.

Ideally the compiler would provide a built-in, but even, for example, an implementation using GCC inline ASM with proper clobbers can do significantly better.

Re: Looking at Unity made me understand the point of C++ coroutines

#109
post #63

Coroutines generally imply some sort of magic to me. I would just go straight to tbb and concurrent_unordered_map! The challenge of parallelism does not come from how to make things parallel, but how you share memory: How you avoid cache misses, make sure threads don't trample each other and design the higher level abstraction so that all layers can benefit from the performance without suffering turnaround problems.…

> some sort of magic to me.

Your stack is on the heap and it contains an instruction pointer to jump to for resume.

Re: Looking at Unity made me understand the point of C++ coroutines

#110
post #27

Earlier quoted context omitted.

Hmm. I'm fairly certain that most of that assembly code for saving/restoring registers can be replaced with setjmp/longjmp, and only control transfer itself would require actual assembly. But maybe not. That's the problem with register machines, I guess. Interestingly enough, BCPL, its main implementation being a p-code interpreter of sorts, has pretty trivially supported coroutines in its "standard" library since th…

You can do a lot of horrible things with setjmp and friends. I actually implemented some exception throw/catch macros using them (which did work) for a compiler that didn't support real C++ exceptions. Thank god we never used them in production code. This would be about 32 years ago - I don't like thinking about that ...

GCC still uses sj/lj by default on some targets to implement exceptions.
Post reply on HN