Coroutinen in C++20

Michael Becker

Was sind Coroutinen ?

  • Verallgemeinerung von Subroutinen
    • Coroutinen können unterbrochen und später wieder fortgesetzt werden
    • Subroutinen sind ein Spezialfall von Coroutinen
    • dennoch sind in C++ Coroutinen normale Funktionen
      • Die Eigenschaft 'Coroutine' ist ein Implementation-Detail
generator<int> macht find zu einer Genteratorfunktion

Exkurs: Function-Stack

Subroutine

find(..)
std::vector<int> const& v
int x
int i
bar()
std::vector<int> v
int pos

Subroutine

bar()
std::vector<int> v
int pos

Stack-Frame wird nach Beendigung der Funktion entfernt

Coroutine

find(..)
std::vector<int> const& v
int x
int i
bar()
std::vector<int> v
int pos

Coroutine

find(..)
std::vector<int> const& v
int x
int i
bar()
std::vector<int> v
int pos

Coroutine

find(..)
std::vector<int> const& v
int x
int i
bar()
std::vector<int> v
int pos

Coroutine

find(..)
std::vector<int> const& v
int x
int i
bar()
std::vector<int> v
int pos

Coroutine

find(..)
std::vector<int> const& v
int x
int i
bar()
std::vector<int> v
int pos

Stack-Frame bleibt erhalten, wenn die Coroutine unterbrochen wird

Exkurs: Coroutinen in C++17

.. oder sogar in C++98

Coroutinen in C++20

nicht weniger verbose
.. dafür aber aufgeräumter
.. more failproof
- erwähnen, dass coroutine-sein ist ein implementation detail - function is coroutine if it uses - co_await - co_yield - or co_return - co_await - if promise has function await_transform, awaitable is promise.await_transform() else awaitable is as-is - then if opertor co_await gives a single best overload, awaiter is the result - promise type: interface for coroutine to comunicate to the outside - coroutine return type: interface for the caller to communicate to the coroutine

Wann is ein Funktion eine Coroutine ?

Eine Funktion ist eine Coroutine, wenn ..

  • .. co_await
  • .. co_yield
  • .. und/oder co_return

.. in ihrer Definition verwendet wird.

Was macht co_await eigentlich?

Expression

Compiler generiert

Customization-Point
  • erlaubt den Suspension-/Resume-Vorgang zu koordinieren
  • await_ready: soll die Coroutine unterbrochen werden?
  • await_suspend: bereitet Unterbrechung vor
  • await_resume: bereitet Fortführung vor

Beispiel


					-start-
					Hello
					-resume-
					Coroutine
					-end-
					

Was passiert beim Aufruf einer Coroutine?

Compiler erzeugt Speicher für das Coroutine-Frame:

  • Funktionsparameter
  • lokale Variablen
  • weiteren Speicher (temporäre Variable, Register, ..)
  • Suspension-Point
  • Promise-Objekt

Zugriff durch std::coroutine_handle<..>

std::coroutine_handle<..> erfüllt NullablePointer Konzept


					-start-
					Hello
					-resume-
					Coroutine
					value: 13279348532
					-end-
					

					-start-
					Hello
					-resume-
					Coroutine
					value: 42
					-end-
					

Yielding

Was macht co_yield eigentlich?

Expression

Compiler generiert


					1
					2
					

Fragen ?

Referenzen

Bonus Slides

Anpassung von bestehenden Typen

Awaitable Transformation

co_await operator overload

custom allocation

stackful "emulation"