yohhoyの日記

技術的メモをしていきたい日記

task_groupコンセプト

C++1y(C++14)に向けた並列プログラミングモデルについてメモ。(PDF)N3711 Task Groups As a Lower Level C++ Library Solution To Fork-Join Parallelismにて、タスク並列処理の基本構成要素となるtask_groupコンセプトが提案されている。なお、同名クラスはIntel TBB(Threading Building Blocks)およびMicrosoft PPL(Parallel Pattern Library)でも提供される。

2014-01-20追記:N3711で言及されるtask_groupコンセプトは、(PDF)N3832 Task Regionにて task_region / task_run / task_wait へと分解されている。

task_groupコンセプトは “タスク並列(task parallel)”(→id:yohhoy:20120417)によるFork-Join並列パターン構築の基本機能を提供する。並列アルゴリズムを提案する(PDF)N3554 A Parallel Algorithms Libraryとは相補的な関係にあり、本N3711はでは最低限のクラス要件を定義するのみ*1
例えば2関数を並行実行するparallel_invoke関数は、task_groupクラスを利用して下記のように実装される(N3711より引用)。同様にparallel_for等の代表的な並列アルゴリズムは、このtask_groupクラスを用いて実装可能。

template <typename Func1, typename Func2>
void parallel_invoke(const Func1& f1, const Func2& f2)
{
  task_group tg(/* ... */);
  tg.run(f1);
  tg.run_and_wait(f2);
}

クラス要件

task_groupクラスは “例外リスト処理ハンドラ” 指定コンストラクタと3つのメンバ関数を提供する。コピー/ムーブ不可。

メンバ関数 説明
template<EH>
task_group(handler)
例外リスト処理ハンドラ(関数オブジェクト)を指定してtask_groupオブジェクトを構築する。
~task_group() waitメンバ関数を呼び出し、必要ならば例外リスト処理ハンドラを呼び出す。
template<F, ...A>
run(func, args)
関数オブジェクトfuncに実引数群argsを渡して呼び出すタスクを生成する。本メンバ関数呼び出しはブロッキングしない。
wait() task_groupオブジェクト上で生成された全タスクが完了するまで待機(ブロッキング)する。
template<F, ...A>
run_and_wait(func, args)
run(func, args); wait();と等価。個別呼び出しに比べて実行時効率改善の余地がある。

“例外リスト処理ハンドラ” にはtask_group::ignore_exceptions(=タスクから送出された例外を全て無視)、もしくは下記シグネチャをもつ関数オブジェクトを指定する*2。生成タスクから送出された例外オブジェクトは例外リスト(exception_list)に保持され、task_groupデストラクタにて例外リストが空でないときのみ “例外リスト処理ハンドラ” が呼び出される。なお “例外リスト処理ハンドラ” 自身が送出する例外は無視される(task_groupデストラクタはnoexcept指定されるため)。

void ExceptionHandler(const exception_list&);

TBB/PPLとの差分

  • task_groupクラスでは “キャンセル機構” を提供しないため、キャンセルしたい場合はタスク処理の一部として記述(協調的キャンセル)する必要がある。TBB/PPLではtask_groupクラスが汎用のキャンセル機構を提供していたが、誤用によるアンチパターンを避けるため削除された。
  • task_groupデストラクタは暗黙的にwaitメンバ関数を呼び出す。TBB/PPLでは明示的にwaitを呼び出す必要があり、未完了タスクが残っている場合はデストラクタから例外送出される。
  • 生成タスクから送出された全ての例外が補足され、task_groupデストラクタにて例外リスト処理ハンドラが呼び出される。TBB/PPLではwaitメンバ関数呼び出し時に生成タスクからの例外が1つだけ再送出される(他タスクからの例外は無視される)。
  • task_group::waitメンバ関数は戻り値型voidかつ例外送出なし。TBB/PPLではキャンセル状態の返却やタスク送出例外の再送出を行う。
  • TBB/PPLで提供されるstructured_task_groupクラスは削除(task_groupクラスに対して実行時効率向上を目的とする)。

関連URL

*1:「生成タスクがどのスレッド上で実行されるか」「タスク・スケジューリングをどのように制御するか」等については一切言及しない。

*2:exception_listクラスは例外オブジェクト(std::exception_ptr)を保持するコンテナ型。詳細はN3554参照