Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++20 coroutines, std return type and state persistancy

This question is actually two questions. I will ask them at once because they may be related.

I just had my first look at C++20 coroutines. If have seen various examples, most of them pretty basic. Like the following:

generator<int> ints(int x)
{
   for (int i = 0; i < x; ++i)
   {
      co_yield i;
   }
}

All of the examples use a special return type that obviously contains the computation result plus the coroutine context. However no example uses a standard return type. They either sneakily omit that type or define a custom nested class that is hard to understand (for me, currently).

1. Does this mean C++20 standard library does not provide coroutine return types that are ready to use e.g. for a generator?

The best I could find was std::coroutine_handle which is internally used by mentioned custom classes.

In the documents it is said that coroutines are a good tool to implement algorithms that require a piece-by-piece data processing and would normally need to be split in fragments e.g. using a (potentially horribly complicated) state engine. I understand that as well. I even remember some project that would have been a great use case for a coroutine, namely loading a large, complex XML file using a streaming interface.

Still there seems to be a big difference: When implementing a state engine, it is pretty easy to store and load the state to/from disk since all state data is available as standard variables (some error checking and file handling is enough). I think of something like a user interface to cancel/resume a long running computation.

2. Is there an (easy) way to store/load a coroutine context to/from permanent storage as well? Is there anything in the C++20 standard that helps in doing so?

like image 272
Silicomancer Avatar asked Sep 28 '20 11:09

Silicomancer


2 Answers

  1. Does this mean C++20 standard library does not provide coroutine return types that are ready to use e.g. for a generator?

It does not. While the Technical Specification proposed all the nuts and bolts for how you might make a type coroutine-compatible, neither it nor any of its revisions proposed any standard coroutine compatible types.

It did provide at least one toy implementation of a generator that, with a little tweaking, could be used.

p2168 formally proposes a std::generator type to be used in coroutines. You may also check out Lewis Baker's cppcoro library.

  1. Is there an (easy) way to store/load a coroutine context to/from permanent storage as well?

The short answer is "no".

Is there anything in the C++20 standard that helps in doing so?

The short answer is also "no".

When a coroutine is created, the compiler will allocate some space on the heap for a coroutine context, this includes local variables and copies/references to parameters. Not totally unlike how there are stack frames for function calls. But, we don't serialize stack frames do we? It doesn't quite make sense.

Think of it this way, if you wanted to serialize a regular function, you would turn it into an object. Like the Command pattern does. The result isn't exactly like a stack frame, but you still have something to call that does what you need.

Coroutines are no different. If you need to serialize/deserialize the state, you'd use a callable object. You could use this object inside a coroutine, but it wouldn't be exactly the same.

like image 154
AndyG Avatar answered Nov 15 '22 01:11

AndyG


There are no library coroutine functions or types in C++20 except the implementation-level handles and traits. You need a coroutine library, which you can build yourself or use from an existing source such as cppcoro.

There is no support for saving a coroutine context to permanent storage. You would have to build that yourself. It would likely have a rather complex implementation.

like image 44
Anthony Williams Avatar answered Nov 15 '22 01:11

Anthony Williams