高度なサンプル#
より高度な結合操作の例として、Foo(i) の最も小さな値を含むインデックスを求めます。シリアルバージョンは、次のようになります。
long SerialMinIndexFoo( const float a[], size_t n ) {
float value_of_min = FLT_MAX; // <climits> からの FLT_MAX
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), // <climits> からの FLT_MAX
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), // <climits> からの FLT_MAX
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;
}