インテル® 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++ クラス・オブジェクトです。