高度なサンプル

高度なサンプル#

より高度な結合操作の例として、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; 
}