インテル® C++ コンパイラー 18.0 デベロッパー・ガイドおよびリファレンス
インテル® Cilk™ Plus は古い機能 (非推奨) です。代わりに、OpenMP* またはインテル® TBB を使用してください。詳細は、「インテル® Cilk™ Plus の代わりに OpenMP* またはインテル® TBB を使用するためのアプリケーションの移行」を参照してください。
この例は、並列に合計を計算するコードにレデューサーを使用する方法を示します。次のようなシリアルプログラムについて考えてみます。この例は、compute() 関数を繰り返し呼び出し、その結果を total 変数に累積します。
#include <iostream> unsigned int compute(unsigned int i) { return i; // i から計算した値を返す } int main(int argc, char* argv[]) { unsigned long long int n = 1000000; unsigned long long int total = 0; // 整数 1..n の合計を計算する for(unsigned int i = 1; i <= n; ++i) { total += compute(i); } // 最初の n 個の整数の合計は n * (n+1) / 2 unsigned long long int correct = (n * (n+1)) / 2; if (total == correct) std::cout << "Total (" << total << ") is correct" << std::endl; else std::cout << "Total (" << total << ") is WRONG, should be " << correct << std::endl; return 0; }
このプログラムをインテル® Cilk™ Plus プログラムに変換します。for ループを cilk_for に変更してループが並列に実行されるようにすると、total 変数でデータ競合が発生します。このデータ競合は、total をレデューサーにすることで解決できます。ここでは、結合則を満たす + 演算子を持つ型のために定義されている reducer<op_add> というレデューサーを使用しています。変更後のプログラムは次のようになります。
#include <cilk/cilk.h> #include <cilk/reducer_opadd.h> #include <iostream> unsigned int compute(unsigned int i) { return i; // i から計算した値を返す } int main(int argc, char* argv[]) { unsigned long long int n = 1000000; cilk::reducer< cilk::op_add<unsigned long long int> > total (0); // 1..n の合計を計算する cilk_for(unsigned int i = 1; i <= n; ++i) { *total += compute(i); } // 最初の N 個の整数の合計は n * (n+1) / 2 unsigned long long int correct = (n * (n+1)) / 2; if ( total.get_value() == correct) std::cout << "Total (" << total.get_value() << ") is correct" << std::endl; else std::cout << "Total (" << total.get_value() << ") is WRONG, should be " << correct << std::endl; return 0; }
シリアルコードへの次の変更は、レデューサーの使用方法を示します。
適切なレデューサー・ヘッダー・ファイル (cilk/reducer_opadd.h) をインクルードします。
リダクション変数を TYPE ではなく、reducer< op_kind<TYPE> > として宣言します。
プログラムを並列化します。ここでは、for ループを cilk_for ループに変更しています。
並列コードでは、オリジナルの変数への参照をレデューサー変数の逆参照 (*total) に変更します。
すべての並列ストランドが同期した後にレデューサーの最終値を取得します。ここでは、cilk_for ループが完了した後に total.get_value() を実行しています。
レデューサーは、コピーまたは割り当てできない C++ クラス・オブジェクトです。