より高度な結合操作のサンプルとして、Foo(i) が最小化されたインデックスを求めます。シリアルバージョンは次のとおりです。
long SerialMinIndexFoo( const float a[], size_t n ) { float value_of_min = FLT_MAX; // FLT_MAX from <climits> long index_of_min = -1; for( size_t i=0; i<n; ++i ) { float value = Foo(a[i]); if( value<value_of_min ) { value_of_min = value; index_of_min = i; } } return index_of_min; }
求めた最小値とそのインデックスを追跡することでループは動作します。これは、ループの反復間で伝達される唯一の情報です。parallel_reduce を使用してループを変換するには、関数オブジェクトは伝達される情報を追跡して、反復が複数のスレッドに分散された場合にこの情報をマージできなければなりません。また、関数オブジェクトは、コンテキストを提供するため、a へのポインターを記録しなければなりません。
次のコードは、完全な関数オブジェクトです。
class MinIndexFoo {
const float *const my_a;
public:
float value_of_min;
long index_of_min;
void operator()( const blocked_range<size_t>& r ) {
const float *a = my_a;
for( size_t i=r.begin(); i!=r.end(); ++i ) {
float value = Foo(a[i]);
if( value<value_of_min ) {
value_of_min = value;
index_of_min = i;
}
}
}
MinIndexFoo( MinIndexFoo& x, split ) :
my_a(x.my_a),
value_of_min(FLT_MAX), // FLT_MAX from <climits>
index_of_min(-1)
{}
void join( const SumFoo& y ) {
if( y.value_of_min<value_of_min ) {
value_of_min = y.value_of_min;
index_of_min = y.index_of_min;
}
}
MinIndexFoo( const float a[] ) :
my_a(a),
value_of_min(FLT_MAX), // FLT_MAX from <climits>
index_of_min(-1),
{}
};
SerialMinIndex は、次のように parallel_reduce を使用して、記述を変更することができます。
long ParallelMinIndexFoo( float a[], size_t n ) { MinIndexFoo mif(a); parallel_reduce(blocked_range<size_t>(0,n), mif );
return mif.index_of_min; }
examples/parallel_reduce/primes ディレクトリーに、parallel_reduce を利用した素数検索のサンプルが含まれています。