Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

"C++20 Coroutines" by Martin Bond

120 views
Skip to first unread message

Lynn McGuire

unread,
Sep 20, 2021, 5:30:30 PM9/20/21
to
"C++20 Coroutines" by Martin Bond
https://blog.feabhas.com/2021/09/c20-coroutines/

"There seems to be a lot of confusion around the implementation of C++20
coroutines, which I think is due to the draft technical specification
for C++20 stating that coroutines are a work in progress so we can’t
expect full compiler and library support at this point in time.
A lot of the problems probably arise from the lack of official
documentation about working with coroutines. We have been given C++
syntax support for coroutines (the co_yield and co_return) but without
all of what I consider full library support. The standard library has
hooks and basic functionality for supporting coroutines, but we must
incorporate this into our own classes. I anticipate that there will be
full library support for generator style coroutines in C++23."

Lynn

Bo Persson

unread,
Sep 21, 2021, 3:28:21 AM9/21/21
to
Yes, this seems to be one of the downsides of the current "no delays"
method of producing the standard revisions. The train leaves the station
on time, but not everyone made it. Some passengers didn't have all their
baggage ready, and were left on the platform.

The opposite, of course, was the C++08 revision where the committee
tried hard to complete everything and it turned out as C++11. Now
everyone got on the train, but 3 years late.

Pros and cons, and all that.


Bonita Montero

unread,
Sep 21, 2021, 5:45:32 AM9/21/21
to
Here, two parts on coroutines of two books about C++20:
https://x0.at/EwrI.pdf

Horsey...@the_stables.com

unread,
Sep 21, 2021, 11:38:09 AM9/21/21
to
Coroutines should have stayed in the microsoft world, not added to the C++
standard. They're a solution looking for a problem.

Bonita Montero

unread,
Sep 21, 2021, 11:40:20 AM9/21/21
to
Coroutines are a solution for a problem which is very often:
state machines that need interaction with a consumer of the
states.

Juha Nieminen

unread,
Sep 22, 2021, 1:23:08 AM9/22/21
to
HorseyWorsey@the_stables.com wrote:
> Coroutines should have stayed in the microsoft world, not added to the C++
> standard. They're a solution looking for a problem.

Coroutines do solve certain problems. It's just that very few people have
ever heard of them, and they are, for some reason, generally very poorly
explained and somewhat hard to understand.

One of the major applications of coroutines is, essentially, being able to
return from a function at any given point (ie. at any point in a function
you can put a command to "return to the caller") and then the calling
code can then tell the function to continue from where it left off.
Coroutines help in, essentially, storing the entire state of the function,
so that it can continue from that exact point, using the exact same state.
Ie. execution can continue from that point forward as if the function
hadn't been exited at all.

Coroutines are compared to cooperative multitasking, and in this sense
they indeed are very similar: In cooperative multitasking at certain
points you can "yield" the execution to the OS, which then later can
return the execution back to that yield point, which will then continue
as if nothing had happened. The entire state of the process is automatically
preserved so that it can continue normally.

You *can* achieve the same effect as coroutines without them, but it
requires you to manually create the data containers where all the
necessary variables are stored so that execution can continue from
the point where it left, and you have to manually create jump statements
to wherever there are these yield points. (The more yield points there
are in your "coroutine", the more conditional gotos are required.)

One practical example of where a coroutine is useful is a library that
decompresses compressed data from a file into a buffer of fixed size.
Whenever the buffer gets full, execution is returned to the caller
for it to consume the contents of the buffer, after which the
execution is returned to the decompressor, which continues from
where it left off. However, since the buffer can typically get full at
several points in the decompressor code, even in the middle of eg.
expanding a block of data, the decompressor needs to somehow store
its exact state in order to know how to continue with the decompression
once execution is resumed. There may be several different places in
the decompression code where stuff is written to the buffer, and at
any moment the buffer may get full. Coroutines can make this whole
thing a lot simpler, as at any point you can just add a yield, with
essentially no extra work to store the state of the decompressor.

Horsey...@the_stables.com

unread,
Sep 22, 2021, 5:26:16 AM9/22/21
to
On Wed, 22 Sep 2021 05:22:59 -0000 (UTC)
Juha Nieminen <nos...@thanks.invalid> wrote:
>You *can* achieve the same effect as coroutines without them, but it
>requires you to manually create the data containers where all the
>necessary variables are stored so that execution can continue from
>the point where it left, and you have to manually create jump statements

Isn't that the point of class methods and variables? Ie: Black boxing state.

>to wherever there are these yield points. (The more yield points there
>are in your "coroutine", the more conditional gotos are required.)

Having multiple yield points sounds like asking for sphagetti code. And thats
before you have to consider recursion in the co-routine and the effect of
threading on it (I have no idea what effects they are but I suspect its messy).

>One practical example of where a coroutine is useful is a library that
>decompresses compressed data from a file into a buffer of fixed size.
>Whenever the buffer gets full, execution is returned to the caller
>for it to consume the contents of the buffer, after which the
>execution is returned to the decompressor, which continues from
>where it left off. However, since the buffer can typically get full at
>several points in the decompressor code, even in the middle of eg.
>expanding a block of data, the decompressor needs to somehow store
>its exact state in order to know how to continue with the decompression
>once execution is resumed. There may be several different places in
>the decompression code where stuff is written to the buffer, and at
>any moment the buffer may get full. Coroutines can make this whole
>thing a lot simpler, as at any point you can just add a yield, with
>essentially no extra work to store the state of the decompressor.

Hmm, not convinced thats any simpler than using object or global state.

Alf P. Steinbach

unread,
Sep 22, 2021, 5:32:11 AM9/22/21
to
On 22 Sep 2021 07:22, Juha Nieminen wrote:
> Coroutines are compared to cooperative multitasking

This is fast becoming the adopted terminology, but really it should be

Continuations are compared to coroutines


- Alf

Bonita Montero

unread,
Sep 22, 2021, 10:40:43 AM9/22/21
to
Am 22.09.2021 um 11:26 schrieb HorseyWorsey@the_stables.com:

>> to wherever there are these yield points. (The more yield points there
>> are in your "coroutine", the more conditional gotos are required.)

> Having multiple yield points sounds like asking for sphagetti code. ...

There is no easy solution. Have you considered the altetrnative
of writing your own state-machine ? That's much worse.

Horsey...@the_stables.com

unread,
Sep 22, 2021, 11:02:07 AM9/22/21
to
I find state machines very clear and easy to follow as well as being explicit
rather than having some stack in an unknown (from the programmers POV) state.

Sam

unread,
Sep 22, 2021, 6:43:45 PM9/22/21
to
HorseyWorsey@the_stables.com writes:

> Coroutines should have stayed in the microsoft world, not added to the C++
> standard. They're a solution looking for a problem.

I was about to make this exact comment. You saved me the trouble of doing
that.

Microsoft hijacked the standardization process in order to get co-routines
into C++. std::threads' poor performance on MS-Windows has been documented,
due to underlying OS design and/or limitations. This was MS's way of
attempting to implement an alternative fake-multithreading that doesn't suck
on their platform.

Bonita Montero

unread,
Sep 22, 2021, 11:39:04 PM9/22/21
to
No, that's much less clearer than having a state like you're in a normal
function.

Juha Nieminen

unread,
Sep 23, 2021, 3:42:32 AM9/23/21
to
HorseyWorsey@the_stables.com wrote:
> On Wed, 22 Sep 2021 05:22:59 -0000 (UTC)
> Juha Nieminen <nos...@thanks.invalid> wrote:
>>You *can* achieve the same effect as coroutines without them, but it
>>requires you to manually create the data containers where all the
>>necessary variables are stored so that execution can continue from
>>the point where it left, and you have to manually create jump statements
>
> Isn't that the point of class methods and variables? Ie: Black boxing state.

I don't understand what that has anything to do with what I wrote.

Classes don't remove the need to manually write them, with all the
variables necessary to retain state, as said.

>>to wherever there are these yield points. (The more yield points there
>>are in your "coroutine", the more conditional gotos are required.)
>
> Having multiple yield points sounds like asking for sphagetti code.

No, yielding precisely *avoids* spaghetti code, because the complexity
is taken care by the compiler rather than explicitly by your code.
You won't have large switch blocks or chained ifs, with gotos or
function calls in each branch, nor separate classes or structs containing
the state of the function. Instead of all that, you have a single
'yield' at every location where you need to return to the caller. After
that the execution continues from there as if nothing had happened.

*Significantly* simpler.

>>One practical example of where a coroutine is useful is a library that
>>decompresses compressed data from a file into a buffer of fixed size.
>>Whenever the buffer gets full, execution is returned to the caller
>>for it to consume the contents of the buffer, after which the
>>execution is returned to the decompressor, which continues from
>>where it left off. However, since the buffer can typically get full at
>>several points in the decompressor code, even in the middle of eg.
>>expanding a block of data, the decompressor needs to somehow store
>>its exact state in order to know how to continue with the decompression
>>once execution is resumed. There may be several different places in
>>the decompression code where stuff is written to the buffer, and at
>>any moment the buffer may get full. Coroutines can make this whole
>>thing a lot simpler, as at any point you can just add a yield, with
>>essentially no extra work to store the state of the decompressor.
>
> Hmm, not convinced thats any simpler than using object or global state.

So you think that a couple of 'yield' instructions here and there is
not any simpler than having to have some class or struct containing the
state of the decompresser, and some chained if, or a switch block, that
jumps wherever the processing was going on at that moment, based on those
state variables?

In that case, I don't know what to say.

Juha Nieminen

unread,
Sep 23, 2021, 3:45:32 AM9/23/21
to
Sam <s...@email-scan.com> wrote:
> Microsoft hijacked the standardization process in order to get co-routines
> into C++. std::threads' poor performance on MS-Windows has been documented,
> due to underlying OS design and/or limitations. This was MS's way of
> attempting to implement an alternative fake-multithreading that doesn't suck
> on their platform.

You seem to have a strange misconception that coroutines are nothing
but simulating multithreading in a single-threaded program.

They are aren't.

Chris M. Thomasson

unread,
Sep 23, 2021, 4:54:04 AM9/23/21
to
Jeeze... This makes me think of the time I was using fibers in windows.
Iirc, it was for sorting things. Also, iirc, it was broken down into,
multiple fibers on a single thread. Multiple threads per process, then
multiple processes. This was so long ago its making my head itch. Back
on WinNT 4.0.

I had to use them in Linux as well. Iirc, setcontext comes to mind. ;^)

Branimir Maksimovic

unread,
Sep 23, 2021, 5:05:30 AM9/23/21
to
coroutines are just same thing as threads except that cancellation points
yield context switch instead of preemptive scheduler, or this way should
be ...

--
7-77-777
\|/
---
/|\

--
/Volumes/air AFP Music Volume/NATASA/temp/peste noire/(2007) Folkfuck Folie/04 - D'un Vilain.mp3

Horsey...@the_stables.com

unread,
Sep 23, 2021, 5:11:20 AM9/23/21
to
On Thu, 23 Sep 2021 05:38:54 +0200
Bonita Montero <Bonita....@gmail.com> wrote:
>Am 22.09.2021 um 17:01 schrieb HorseyWorsey@the_stables.com:
>> On Wed, 22 Sep 2021 16:40:31 +0200
>> Bonita Montero <Bonita....@gmail.com> wrote:
>>> Am 22.09.2021 um 11:26 schrieb HorseyWorsey@the_stables.com:
>>>
>>>>> to wherever there are these yield points. (The more yield points there
>>>>> are in your "coroutine", the more conditional gotos are required.)
>>>
>>>> Having multiple yield points sounds like asking for sphagetti code. ...
>>>
>>> There is no easy solution. Have you considered the altetrnative
>>> of writing your own state-machine ? That's much worse.
>>
>> I find state machines very clear and easy to follow as well as being explicit
>
>> rather than having some stack in an unknown (from the programmers POV) state.
>
>
>No, that's much less clearer than having a state like you're in a normal
>function.

That is a matter of opinion.

Horsey...@the_stables.com

unread,
Sep 23, 2021, 5:15:03 AM9/23/21
to
On Thu, 23 Sep 2021 07:42:22 -0000 (UTC)
Juha Nieminen <nos...@thanks.invalid> wrote:
>HorseyWorsey@the_stables.com wrote:
>> On Wed, 22 Sep 2021 05:22:59 -0000 (UTC)
>> Juha Nieminen <nos...@thanks.invalid> wrote:
>>>You *can* achieve the same effect as coroutines without them, but it
>>>requires you to manually create the data containers where all the
>>>necessary variables are stored so that execution can continue from
>>>the point where it left, and you have to manually create jump statements
>>
>> Isn't that the point of class methods and variables? Ie: Black boxing state.
>
>I don't understand what that has anything to do with what I wrote.
>
>Classes don't remove the need to manually write them, with all the
>variables necessary to retain state, as said.

Where did I say they did? I'm saying the point of them is to black box state,
not that it doesn't require any effort to attain that.

>> Having multiple yield points sounds like asking for sphagetti code.
>
>No, yielding precisely *avoids* spaghetti code, because the complexity
>is taken care by the compiler rather than explicitly by your code.
>You won't have large switch blocks or chained ifs, with gotos or
>function calls in each branch, nor separate classes or structs containing
>the state of the function. Instead of all that, you have a single
>'yield' at every location where you need to return to the caller. After
>that the execution continues from there as if nothing had happened.

Oh sure, just do a co_call or co_resume, obvious where it'll go. Not. Its
a magical mystery tour of the code dependent on the stack. At least state
machines are explicit.

>*Significantly* simpler.

Syntatically maybe.

>> Hmm, not convinced thats any simpler than using object or global state.
>
>So you think that a couple of 'yield' instructions here and there is
>not any simpler than having to have some class or struct containing the
>state of the decompresser, and some chained if, or a switch block, that
>jumps wherever the processing was going on at that moment, based on those
>state variables?

Yes.

>In that case, I don't know what to say.

Good, say nothing. We'll just have to disagree.

Juha Nieminen

unread,
Sep 24, 2021, 12:42:17 AM9/24/21
to
HorseyWorsey@the_stables.com wrote:
>>So you think that a couple of 'yield' instructions here and there is
>>not any simpler than having to have some class or struct containing the
>>state of the decompresser, and some chained if, or a switch block, that
>>jumps wherever the processing was going on at that moment, based on those
>>state variables?
>
> Yes.

Then I don't know what to say. Rather than perhaps question your sanity.

Bonita Montero

unread,
Sep 24, 2021, 12:16:02 PM9/24/21
to
Am 23.09.2021 um 11:05 schrieb Branimir Maksimovic:
> On 2021-09-23, Bonita Montero <Bonita....@gmail.com> wrote:
>> Am 22.09.2021 um 17:01 schrieb HorseyWorsey@the_stables.com:
>>> On Wed, 22 Sep 2021 16:40:31 +0200
>>> Bonita Montero <Bonita....@gmail.com> wrote:
>>>> Am 22.09.2021 um 11:26 schrieb HorseyWorsey@the_stables.com:
>>>>
>>>>>> to wherever there are these yield points. (The more yield points there
>>>>>> are in your "coroutine", the more conditional gotos are required.)
>>>>
>>>>> Having multiple yield points sounds like asking for sphagetti code. ...
>>>>
>>>> There is no easy solution. Have you considered the altetrnative
>>>> of writing your own state-machine ? That's much worse.
>>>
>>> I find state machines very clear and easy to follow as well as being explicit
>>> rather than having some stack in an unknown (from the programmers POV) state.
>>
>> No, that's much less clearer than having a state like you're in a normal
>> function.
> coroutines are just same thing as threads ...

No, they're similar to fiberes - with much less overhead.

Bonita Montero

unread,
Sep 24, 2021, 12:17:13 PM9/24/21
to
That's not a matter of opinion. If you've managed to write a complex
sate-machine you honor the convenience and readability of coroutines.

Bonita Montero

unread,
Sep 24, 2021, 12:19:26 PM9/24/21
to
Am 23.09.2021 um 09:42 schrieb Juha Nieminen:

> No, yielding precisely *avoids* spaghetti code, ...

State-machines are _always_ spahgetti-code (while( !end )
switch( state ) { ... }), even when you write them conventionally.
But coroutines are _much_ more readable and maintainable.

Ben Bacarisse

unread,
Sep 24, 2021, 4:07:40 PM9/24/21
to
Bonita Montero <Bonita....@gmail.com> writes:

> State-machines are _always_ spahgetti-code (while( !end )
> switch( state ) { ... }), even when you write them conventionally.

Obviously one person's spaghetti is another person's farfalle, but in my
opinion, if the state is a (a pointer to a) function that returns (a
pointer to) the next state, then you just get a clean loop calling a
function:

data d = { ... };
State state = initial;
while (state) state = (State)state(&d);

C++ has trouble writing the recursive type, so you need a cast, but it's
a safe cast.

--
Ben.

Sam

unread,
Sep 24, 2021, 7:21:20 PM9/24/21
to
And I never said they are. They are not a simulation of multithreading.
They're a failed simulation of multithreading, on a platform with a rather
bad native implementation of multiple execution threads.

Branimir Maksimovic

unread,
Sep 24, 2021, 8:57:34 PM9/24/21
to
And fibbers are what ? ;P
much of muchness :P

--
7-77-777
\|/
---
/|\

--
Evil Sinner!

Branimir Maksimovic

unread,
Sep 24, 2021, 8:59:01 PM9/24/21
to
State machines are spagetty if not OO. Think about it.

--
7-77-777
\|/
---
/|\

On 2021-09-24, Bonita Montero <Bonita....@gmail.com> wrote:
--
Evil Sinner!

Horsey...@the_stables.com

unread,
Sep 25, 2021, 5:20:09 AM9/25/21
to
On Fri, 24 Sep 2021 18:17:02 +0200
No sane person would use coroutines instead of a nice clear state machine.
How the fuck are you supposed to debug a coredump from something that uses
coroutines? You have absolutely no idea what state its in until you step
through to the call itself or feel like reading a stack dump! With a state
machine you just dump the state variable(s). Even the cppreference example
code for coroutines is an alphabet soup whereas normally their examples are
pretty clear.

This garbage paradigm should never have been included in C++ but it would seem
MS have the committee in its pocket.

Horsey...@the_stables.com

unread,
Sep 25, 2021, 5:20:35 AM9/25/21
to
LMFAO!!!!!!

Horsey...@the_stables.com

unread,
Sep 25, 2021, 5:28:54 AM9/25/21
to
On Fri, 24 Sep 2021 19:21:10 -0400
Sam <s...@email-scan.com> wrote:
>This is a MIME GnuPG-signed message. If you see this text, it means that
>your E-mail or Usenet software does not support MIME signed messages.
>The Internet standard for MIME PGP messages, RFC 2015, was published in 1996.
>To open this message correctly you will need to install E-mail or Usenet
>software that supports modern Internet standards.
>
>--=_monster.email-scan.com-165744-1632525670-0001
>Content-Type: text/plain; format=flowed; delsp=yes; charset="UTF-8"
>Content-Disposition: inline
>Content-Transfer-Encoding: 7bit
And a diabolical implementation of process spawning.

Bonita Montero

unread,
Sep 25, 2021, 6:00:24 AM9/25/21
to
State-machines are never clear ! You've to write a
while( state != END )
switch( state )
{
case STATE_A:
...
break;
case STATE_B:
...
break;
case STATE_C:
...
break;
}
-loop and that's _much_ less readable.

> How the fuck are you supposed to debug a coredump from something that uses
> coroutines? ...

The coroutine-frame is a block of memory of the promise.
It should be debuggable.

Horsey...@the_stables.com

unread,
Sep 25, 2021, 6:10:05 AM9/25/21
to
I do hope you're joking.

>> How the fuck are you supposed to debug a coredump from something that uses
>> coroutines? ...
>
>The coroutine-frame is a block of memory of the promise.
>It should be debuggable.

Oh please, don't make me laugh.

Bonita Montero

unread,
Sep 25, 2021, 6:18:18 AM9/25/21
to
Am 25.09.2021 um 12:09 schrieb HorseyWorsey@the_stables.com:

>> Am 25.09.2021 um 11:19 schrieb HorseyWorsey@the_stables.com:
>>> No sane person would use coroutines instead of a nice clear state machine.
>>
>> State-machines are never clear ! You've to write a
>> while( state != END )
>> switch( state )
>> {
>> case STATE_A:
>> ...
>> break;
>> case STATE_B:
>> ...
>> break;
>> case STATE_C:
>> ...
>> break;
>> }
>> -loop and that's _much_ less readable.

With C++-coroutines you have the control-flow of a normal func-
tion between the states. That's much more readable than the above
spaghetti-code. That's while fibers have been invented, but their
overhead is much larger and they're not integrated in the langauage
and thereby not so convenient.

Horsey...@the_stables.com

unread,
Sep 25, 2021, 6:39:16 AM9/25/21
to
On Sat, 25 Sep 2021 12:18:09 +0200
Bonita Montero <Bonita....@gmail.com> wrote:
>Am 25.09.2021 um 12:09 schrieb HorseyWorsey@the_stables.com:
>
>>> Am 25.09.2021 um 11:19 schrieb HorseyWorsey@the_stables.com:
>>>> No sane person would use coroutines instead of a nice clear state machine.
>>>
>>> State-machines are never clear ! You've to write a
>>> while( state != END )
>>> switch( state )
>>> {
>>> case STATE_A:
>>> ...
>>> break;
>>> case STATE_B:
>>> ...
>>> break;
>>> case STATE_C:
>>> ...
>>> break;
>>> }
>>> -loop and that's _much_ less readable.
>
>With C++-coroutines you have the control-flow of a normal func-
>tion between the states. That's much more readable than the above
>spaghetti-code.

Bollocks. Coroutines are the equivalent of a load of hidden static function
variables that will be very difficult to interrogate during debugging. But
then you seem to think the sun shines out of Microsofts backside and everything
they come up with is amazing.


Bonita Montero

unread,
Sep 25, 2021, 6:42:20 AM9/25/21
to
Am 25.09.2021 um 12:39 schrieb HorseyWorsey@the_stables.com:
> On Sat, 25 Sep 2021 12:18:09 +0200
> Bonita Montero <Bonita....@gmail.com> wrote:
>> Am 25.09.2021 um 12:09 schrieb HorseyWorsey@the_stables.com:
>>
>>>> Am 25.09.2021 um 11:19 schrieb HorseyWorsey@the_stables.com:
>>>>> No sane person would use coroutines instead of a nice clear state machine.
>>>>
>>>> State-machines are never clear ! You've to write a
>>>> while( state != END )
>>>> switch( state )
>>>> {
>>>> case STATE_A:
>>>> ...
>>>> break;
>>>> case STATE_B:
>>>> ...
>>>> break;
>>>> case STATE_C:
>>>> ...
>>>> break;
>>>> }
>>>> -loop and that's _much_ less readable.
>>
>> With C++-coroutines you have the control-flow of a normal func-
>> tion between the states. That's much more readable than the above
>> spaghetti-code.
>
> Bollocks. Coroutines are the equivalent of a load of hidden static function
> variables that will be very difficult to interrogate during debugging.

If you write state-machines on your own the state isn't kept on the
stack as well.

Horsey...@the_stables.com

unread,
Sep 25, 2021, 6:44:27 AM9/25/21
to
On Sat, 25 Sep 2021 12:42:10 +0200
It doesn't matter where the state variable(s) are kept, the point is they're
easily accessable and modifiable in a debugger.

Bonita Montero

unread,
Sep 25, 2021, 7:14:51 AM9/25/21
to
That's part of your promise and can be inspected with a C++20-capable
debugger.

Branimir Maksimovic

unread,
Sep 25, 2021, 8:32:41 AM9/25/21
to
On 2021-09-25, HorseyWorsey@the_stables.com <HorseyWorsey@the_stables.com> wrote:
> On Fri, 24 Sep 2021 18:17:02 +0200
>
> No sane person would use coroutines instead of a nice clear state machine.
> How the fuck are you supposed to debug a coredump from something that uses
> coroutines? You have absolutely no idea what state its in until you step
> through to the call itself or feel like reading a stack dump! With a state
> machine you just dump the state variable(s). Even the cppreference example
> code for coroutines is an alphabet soup whereas normally their examples are
> pretty clear.
>
> This garbage paradigm should never have been included in C++ but it would seem
> MS have the committee in its pocket.

Coroutines are nice for ones that debug in different ways.
Don't take tool because it is not appropropriate TO YOU.
it's selfish...
>


--
7-77-777
Evil Sinner!

Branimir Maksimovic

unread,
Sep 25, 2021, 8:38:19 AM9/25/21
to
> And a diabolical implementation of process spawning.

Well if done properly it's just preemptive shceduler
that can schedule on single or multiple cores/cpus
>


--
7-77-777
Evil Sinner!

Branimir Maksimovic

unread,
Sep 25, 2021, 8:44:15 AM9/25/21
to
On 2021-09-25, Bonita Montero <Bonita....@gmail.com> wrote:
>
> That's part of your promise and can be inspected with a C++20-capable
> debugger.
Which one?

--
7-77-777
Evil Sinner!

Alf P. Steinbach

unread,
Sep 25, 2021, 9:14:55 AM9/25/21
to
On 20 Sep 2021 23:30, Lynn McGuire wrote:
> "C++20 Coroutines" by Martin Bond
>    https://blog.feabhas.com/2021/09/c20-coroutines/
>
> "There seems to be a lot of confusion around the implementation of C++20
> coroutines, which I think is due to the draft technical specification
> for C++20 stating that coroutines are a work in progress so we can’t
> expect full compiler and library support at this point in time.
> A lot of the problems probably arise from the lack of official
> documentation about working with coroutines. We have been given C++
> syntax support for coroutines (the co_yield and co_return) but without
> all of what I consider full library support. The standard library has
> hooks and basic functionality for supporting coroutines, but we must
> incorporate this into our own classes. I anticipate that there will be
> full library support for generator style coroutines in C++23."

The main confusion about C++20 “coroutines” is that they're general
coroutines.

They're not: they're simple continuations, the special case of
/stackless/ coroutines (no dedicated stack for each coroutine).

While that's nice performance-wise it's very limited, and the Microsoft
style support framework adopted in C++20 requires you to build a full
fledged star ship in order to lift a little pebble; it's, well, moronic.

---

I once started coding up real coroutines in terms of standard C++ threads.

That could be very useful, in contrast to the mostly useless C++17
continuations.

However, I stopped fiddling with it when the complexity of the
implementation overwhelmed me. No doubt because of a lack of experience
in safe multi-tasking. It would be really nice if SOMEONE could do this:
real general coroutines, by leveraging real C++ threads.

---

That could open the world of safe multi-tasking to C++ programmers in
general.

Another such enabler: an implementation of Ada-like rendezvous.

And, and, ... Occam-like channels, maybe. :)


- Alf

Bonita Montero

unread,
Sep 25, 2021, 9:58:25 AM9/25/21
to
Am 25.09.2021 um 14:44 schrieb Branimir Maksimovic:
> On 2021-09-25, Bonita Montero <Bonita....@gmail.com> wrote:
>>
>> That's part of your promise and can be inspected with a C++20-capable
>> debugger.
> Which one?

VS 2020 beta.

Branimir Maksimovic

unread,
Sep 25, 2021, 10:00:06 AM9/25/21
to
On 2021-09-25, Bonita Montero <Bonita....@gmail.com> wrote:
> Am 25.09.2021 um 14:44 schrieb Branimir Maksimovic:
>> On 2021-09-25, Bonita Montero <Bonita....@gmail.com> wrote:
>>>
>>> That's part of your promise and can be inspected with a C++20-capable
>>> debugger.
>> Which one?
>
> VS 2020 beta.

i am still on 2-17, didn't like 2-19. Let's try 2020 when I have time...
>


--
7-77-777
Evil Sinner!

Bonita Montero

unread,
Sep 25, 2021, 10:23:15 AM9/25/21
to
Am 25.09.2021 um 15:59 schrieb Branimir Maksimovic:
> On 2021-09-25, Bonita Montero <Bonita....@gmail.com> wrote:
>> Am 25.09.2021 um 14:44 schrieb Branimir Maksimovic:
>>> On 2021-09-25, Bonita Montero <Bonita....@gmail.com> wrote:
>>>>
>>>> That's part of your promise and can be inspected with a C++20-capable
>>>> debugger.
>>> Which one?
>>
>> VS 2020 beta.
>
> i am still on 2-17, didn't like 2-19. Let's try 2020 when I have time...

I think sooner or later all C++IDEs will have the capabilility to debug
inspect the state inside the promise of a coroutine.

Horsey...@the_stables.com

unread,
Sep 25, 2021, 11:04:52 AM9/25/21
to
On Sat, 25 Sep 2021 13:14:40 +0200
Oh very useful. So not only do you need a cutting edge debugger which might
not be available in all execution enviroments, you have to interrogate a
compiler generated object too. So simple compared to state variables!

Horsey...@the_stables.com

unread,
Sep 25, 2021, 11:29:04 AM9/25/21
to
Quelle surprise!

Bonita Montero

unread,
Sep 25, 2021, 12:45:04 PM9/25/21
to
> Oh very useful. So not only do you need a cutting edge debugger which might
> not be available in all execution enviroments, you have to interrogate a
> compiler generated object too. So simple compared to state variables!

You can be assured that in the near future most C++-capable debuggers
will support that.

Manfred

unread,
Sep 25, 2021, 5:08:16 PM9/25/21
to
I'm no expert in coroutines, but AFAIU their main advantage is to enable
multitasking without the overhead of multithreading.
In order to achieve this, language support is needed that was just not
available prior to C++20 (and even with C++20 such support is limited,
so that only the subset of continuations is actually available, as you say)

The point being, if you try to do that using threads kind of defeats the
purpose, doesn't it?
(even if you build this with full synchronization inside, you'll still
pay the price of performance and resource usage, which can be relevant
for this kind of thing)

Alf P. Steinbach

unread,
Sep 25, 2021, 7:50:12 PM9/25/21
to
What you write is an advantage of continuations compared to general
coroutines. I consider that a very marginal advantage. Correctness is
far, far more important than some micro-efficiency.

The advantage of general coroutines is that they enable multi-tasking
(namely cooperative multi-tasking) without the severe synchronization
problems of general threads or processes.

Coroutines don't automagically deal with all kinds of multi-tasking
problems, in particular deadlocks are still possible, but you don't have
two or more threads possibly accessing the same thing at a time, since
only one coroutine executes at a time.


> In order to achieve this, language support is needed that was just not
> available prior to C++20 (and even with C++20 such support is limited,
> so that only the subset of continuations is actually available, as you say)

True, but I fail to see any reason, and I haven't yet seen anybody able
to cough up a reason, to have continuations in C++.


> The point being, if you try to do that using threads kind of defeats the
> purpose, doesn't it?

No (you misunderstood the purpose).

Doing this could open the world of safe multi-tasking to C++ programmers
in general.

Oh, I already wrote that, sorry.


> (even if you build this with full synchronization inside, you'll still
> pay the price of performance and resource usage, which can be relevant
> for this kind of thing)

Yes, it must be built with synchronization inside, and like threads each
general coroutine needs its own stack, which is another cost: firing up
a general coroutine generally involves a dynamic allocation (though I
guess with language support it's technically possible to use statically
allocated stack areas when the number of coroutines has a reasonably low
upper bound, but such support would be needed for that because standard
threads don't provide any means to influence the per-thread stacks).


>> Another such enabler: an implementation of Ada-like rendezvous.
>>
>> And, and, ... Occam-like channels, maybe. :)

I forgot to mention Linda.

Oh well.


- Alf

Horsey...@the_stables.com

unread,
Sep 26, 2021, 10:15:54 AM9/26/21
to
In the real world as opposed to your toy home dev enviroment, compilers
and debuggers do not get updated very often because they have to be
thoroughly tested to make sure they don't break the code or cause some other
issue. Keeping a business running is more important than having the latest
bleeding edge language features.

Manfred

unread,
Sep 26, 2021, 1:12:28 PM9/26/21
to
Correctness is the precondition, obviously, but this is not about
micro-efficiency (see below)

>
> The advantage of general coroutines is that they enable multi-tasking
> (namely cooperative multi-tasking) without the severe synchronization
> problems of general threads or processes.

Yes, what you call "severe synchronization problems" is part of what I
called "overhead". (I tend to write in a very concise way - that is
meant both as "coding overhead" and "resource usage overhead")

>
> Coroutines don't automagically deal with all kinds of multi-tasking
> problems, in particular deadlocks are still possible, but you don't have
> two or more threads possibly accessing the same thing at a time, since
> only one coroutine executes at a time.

Yes, that was clear.

>
>
>> In order to achieve this, language support is needed that was just not
>> available prior to C++20 (and even with C++20 such support is limited,
>> so that only the subset of continuations is actually available, as you
>> say)
>
> True, but I fail to see any reason, and I haven't yet seen anybody able
> to cough up a reason, to have continuations in C++.

Aren't continuations in C++20? Do you mean general coroutines?
If that is the case, the fact that POSIX has (had) support for them
would suggest that it should be possible, then the fact that they
dropped it may also suggest that there are counter indications of some
sort, but I agree that still the question for explanation stands.

>
>
>> The point being, if you try to do that using threads kind of defeats
>> the purpose, doesn't it?
>
> No (you misunderstood the purpose).
Not entirely (see above)

>
> Doing this could open the world of safe multi-tasking to C++ programmers
> in general.
>
> Oh, I already wrote that, sorry.
So, you mean make life easier for C++ programmers that are not
comfortable with multithreaded programming, fair enough. ("open the
world" sounded to me like there would be something more involved).

>
>
>> (even if you build this with full synchronization inside, you'll still
>> pay the price of performance and resource usage, which can be relevant
>> for this kind of thing)
>
> Yes, it must be built with synchronization inside, and like threads each
> general coroutine needs its own stack, which is another cost: firing up
> a general coroutine generally involves a dynamic allocation (though I
> guess with language support it's technically possible to use statically
> allocated stack areas when the number of coroutines has a reasonably low
> upper bound, but such support would be needed for that because standard
> threads don't provide any means to influence the per-thread stacks).
>
Referring to the first "see below" above: there are multiple performance
costs involved with firing up multiple threads - whether these costs
fall into the category of "micro-efficiency" depends on the context.

AFAIU coroutines are especially used (or at least advocated for) in
areas like high-throughput server processes, real time systems, and
architectures with strict resource constraints. This is why I wrote
performance might be relevant for this kind of thing.

As to how it works, with POSIX I found "man makecontext" interesting (on
any decent Linux box or the appropriate POSIX documentation).
But then, support for this has been removed in POSIX.1-2008, so probably
it's not that pressing of a need.

Juha Nieminen

unread,
Sep 27, 2021, 1:39:42 AM9/27/21
to
Branimir Maksimovic <branimir....@gmail.com> wrote:
> State machines are spagetty if not OO. Think about it.

Off-topic, but could you please stop top-posting? It's annoying.

Just edit the original post, leaving the relevant part you are
responding to, and write your response below. Like I'm doing here.

Juha Nieminen

unread,
Sep 27, 2021, 1:42:23 AM9/27/21
to
Sam <s...@email-scan.com> wrote:
>> Sam <s...@email-scan.com> wrote:
>> > Microsoft hijacked the standardization process in order to get co-routines
>> > into C++. std::threads' poor performance on MS-Windows has been documented,
>> > due to underlying OS design and/or limitations. This was MS's way of
>> > attempting to implement an alternative fake-multithreading that doesn't
>> suck
>> > on their platform.
>>
>> You seem to have a strange misconception that coroutines are nothing
>> but simulating multithreading in a single-threaded program.
>>
>> They are aren't.
>
> And I never said they are. They are not a simulation of multithreading.
> They're a failed simulation of multithreading, on a platform with a rather
> bad native implementation of multiple execution threads.

My claim still stands. You did nothing to refute it. You seem to have this
strange misconception that coroutines are only about simulating
multithreading, and nothing else. Whether you think they are a good or
a bad feature is completely irrelevant to this.

Bonita Montero

unread,
Sep 28, 2021, 1:24:49 AM9/28/21
to
This feature is trivial to update because the variables of
a cououtine are simply a normal compiler-generated struct.

Branimir Maksimovic

unread,
Sep 28, 2021, 10:30:19 PM9/28/21
to
I haven't mentioned that. Sure I can post normally, no problem,
i just wanted to MAKE A POINT :P

--

7-77-777
Evil Sinner!

Tim Rentsch

unread,
Oct 6, 2021, 4:19:26 PM10/6/21
to
Ben Bacarisse <ben.u...@bsb.me.uk> writes:

> Bonita Montero <Bonita....@gmail.com> writes:
>
>> State-machines are _always_ spahgetti-code (while( !end )
>> switch( state ) { ... }), even when you write them conventionally.
>
> Obviously one person's spaghetti is another person's farfalle, but
> in my opinion, if the state is a (a pointer to a) function that
> returns (a pointer to) the next state, then you just get a clean
> loop calling a function:
>
> data d = { ... };
> State state = initial;
> while (state) state = (State)state(&d);
>
> C++ has trouble writing the recursive type, so you need a cast, but
> its a safe cast.

In C++, needing a cast can be avoided by wrapping the function
pointer in a class or struct, as for example:

class State {
typedef State (*Go)( data & );
Go go;

public:
State( Go g ) : go( g ) {}

operator bool(){ return go; }

State operator()( data &data ){
return go( data );
}
};


void
run_state_machine( State initial, data &data ){
State s = initial;
while( s ) s = s( data );
}

The example above is specific to a partcular type of "data" being
acted on, but it's easy to generalize around that shortcoming by
using templates.
0 new messages