yohhoyの日記

2018-04-15

C++コルーチン拡張メモ(N4736)

プログラミング言語C++のコルーチン(Coroutines)拡張に関するメモ。2018年4月現在、C++2a(C++20)言語仕様での正式採択に向けた検討が進んでいる。

本記事の内容は(PDF)N4736 Working Draft, C++ Extensions for Coroutinesに基づく。

C++コルーチン拡張はコルーチンに関するC++言語仕様と低レベルAPIのみを規定し、他プログラミング言語のような具体的な“コルーチン”機能は何も定義しない。

  • C++コルーチンライブラリ実装者は、低レベルAPIを用いてジェネレータ(Generator)や非同期タスク(Asynchronous task)といった具象機能を提供する。
  • C++アプリケーション開発者は、co_xxxキーワードを介してコルーチンライブラリを利用する。

要約:

  • 新しいキーワード:co_yield, co_return, co_await
  • 新しい構文:yield式, co_return文, await式, co_await範囲for文
  • 新しいヘッダ:<experimental/coroutine>*1
  • コルーチン(coroutine) == 関数途中での中断(suspend)/再開(resume)を追加サポートする関数(function)*2
  • コルーチン(coroutine) == 本体にco_yield/co_return/co_awaitキーワードを含む関数*3
    • 制限:main関数、コンストラクタ、デストラクタはコルーチンになれない。関数戻り値型推論とコルーチンは併用不可。コルーチンへのconstexpr指定不可。returnco_returnは排他的。
  • C++コルーチン拡張では、コルーチン動作に関するユーザ定義型のカスタマイゼーション・ポイント(customization point)を定める*4
    • yield文とco_return文はユーザ定義“コルーチン型(coroutine type)”を介して、await文とco_await範囲for文はユーザ定義“Awaitable型”を介してその振る舞いを定義する。
    • コルーチン外部仕様としては、コルーチン制御フローのための“コルーチンハンドラ(coroutine handler)”*5を内包した“コルーチン型(coroutine type)”を返す。
    • コルーチン内部実装では、ユーザ定義“プロミス型(promise type)”の“プロミスオブジェクト(promise object)”が暗黙に生成され、“コルーチン型(coroutine type)”戻り値との紐付けを行う。
    • コルーチン制御フローはco_yieldco_awaitによって中断(suspend)され、“コルーチンハンドラ(coroutine handler)”を介して再開(resume)される。
    • コルーチン(coroutine)とスレッド(thread)は直交した機能。あるスレッドで中断(suspend)したコルーチンを、他スレッド上にて再開(resume)可能。*6
  • スタックレス・コルーチン(stackless coroutine)のみサポート。
  • 非対称(asymmetric)/対称(symmetric)コルーチンいずれもサポート。*7
  • コルーチン内部実装では、暗黙に“コルーチン・フレーム(corotuine frame)”動的メモリ確保/解放処理が行われる。ただし、一定条件をみたせばコンパイラによるヒープ確保省略(heap allocation elision)最適化を期待できる。*8

ノート:アプリケーション開発者視点でのC++コルーチン拡張の恩恵は、lewissbaker/cppcoroライブラリP0975R0 Impact of coroutines on current and upcoming library facilitiesが参考になる。低レベルAPIを用いたナイーブ実装はC++コルーチン拡張メモ参照。

関連URL

*1:TS(Technical Specification)から正式機能に昇格すれば、ヘッダ<coroutine>に変更される。P0912R0参照。

*2:通常関数(サブルーチン; subroutine)制御フローは呼び出し(call)/戻り(return)のみサポートするのに対し、コルーチン(coroutine)制御フローは呼び出し(call)/中断(suspend)/再開(resume)/戻り(return)に拡張されている。つまりコルーチンはより汎化された関数(サブルーチン)と解釈される。

*3:関数プロトタイプ宣言からは、通常の関数かコルーチンのいずれかを判断できない。

*4:本記事における「ユーザ定義」のユーザは、通常のアプリケーション開発者ではなく、コルーチンライブラリの実装者を意味する。

*5std::experimental::coroutine_handler<Promise>Promiseはプロミス型(promise type))

*6:コルーチンとスレッド併用時のスレッド安全性(thread safety)担保は、これまで同様にコルーチンライブラリ開発者およびアプリケーション開発者の責任となる。

*7http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0913r1.html

*8http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0981r0.html

スパム対策のためのダミーです。もし見えても何も入力しないでください
ゲスト


画像認証

トラックバック - http://d.hatena.ne.jp/yohhoy/20180415/p1