インテル® C++ コンパイラー 18.0 デベロッパー・ガイドおよびリファレンス
インテル® Cilk™ Plus は古い機能 (非推奨) です。代わりに、OpenMP* またはインテル® TBB を使用してください。詳細は、「インテル® Cilk™ Plus の代わりに OpenMP* またはインテル® TBB を使用するためのアプリケーションの移行」を参照してください。
前のセクションでは、DAG を使用してインテル® Cilk™ Plus プログラムのシリアル/並列構造について説明しました。DAG はプロセッサー・コア数に依存しないことを思い起こしてください。実行モデルは、ランタイム・スケジューラーがストランドをワーカーに割り当てる方法を表します。
プログラムを並列化すると、複数のストランドが並列で実行されます。ただし、インテル® Cilk™ Plus プログラムでは、必ずしもストランドを並列で実行しなければならないわけではありません。スケジューラーは、ストランドを並列で実行するかどうかを動的に決定します。
次のようなプログラムについて考えてみます。
do_init_stuff(); // ストランド 1 の実行 cilk_spawn func3(); // ストランド 3 (「子」) のスポーン do_more_stuff(); // ストランド 2 (「継続」) の実行 cilk_sync; do_final_stuff; // ストランド 4 の実行
次にこのコードの簡単な DAG を示します。
ワーカーは、インテル® Cilk™ Plus プログラムを実行する OS スレッドです。複数のワーカーがある場合、このプログラムの実行方法は 2 つあります。
プログラム全体を 1 つのワーカーで実行する
スケジューラーによって、ストランド (2) と (3) をそれぞれ別々のワーカーで実行するように選択される
シリアル・セマンティクスを保証するために、スポーンされる関数 (子関数、またはこの例ではストランド (3)) は、常にスポーンを開始するストランドを実行しているのと同じワーカーによって実行されます。そのため、この例では、ストランド (1) とストランド (3) は常に同じワーカーで実行されます。
ストランドを実行可能なワーカーがある場合は、ストランド (2) ("継続処理") は異なるワーカーで実行されます。これはスチールと呼ばれ、継続処理が新しいワーカーにとられた場合に発生します。
この 2 つの実行方法を理解するためには、新しい図が役に立ちます。次の図は、1 つのワーカーで実行した場合を示しています。
2 つ目のワーカーがスケジュールされると、そのワーカーは継続処理 (ストランド (2)) の実行を開始し、1 つ目のワーカーは (B) の sync に進みます。次の図では、ストランド (2) の点線が 2 つ目のワーカーを示しています。sync の後に、ストランド (4) はいずれかのワーカーによって続行されます。このプログラムでは、ストランド (4) は sync に最後に到達したワーカーによって実行されます。
実行モデルの詳細は、ワーカーとシステムスレッド間の相互作用のセクションとレデューサーのセクションで説明しています。ここでは要点のみ説明します。
cilk_spawn された子は常に呼び出し元と同じワーカー (システムスレッド) で実行されます。
cilk_spawn 後の継続処理は別のワーカーで実行することもできます。その場合、継続処理は別のワーカーによってスチールされたといいます。
cilk_sync の後、ストランドを実行し sync に達した任意のワーカーで処理を続行することができます。
プログラムを複数のワーカーで実行すると、各ワーカーは現在実行中のストランドのペディグリーを追跡します。インテル® Cilk™ Plus は、各ワーカーが現在実行中のストランドのペディグリーを問い合わせることができる API を提供しています。この API は、新しい最大ストランド境界を作成する呼び出しも提供します。この呼び出しは、現在の最大ストランドを終了し、異なるペディグリーで新しい最大ストランドを開始します。