この例は、x =1 から 10 までの x*x + x*x*x を計算します。 この例のレイアウトは、下記の図のようになります。
各値は、input_node<int> input から処理されます。 このノードは、値を squarer (x*x を計算) および cuber (x*x*x を計算) にブロードキャストします。 これらのノードの出力は、join のポートの 1 つに格納されます。 join_node< tuple<int,int> > join で両方の値を含むタプルが作成され、summer (両方の値を合計に追加) に送られます。 squarer と cuber はどちらも無制限に並列化できます。つまり、複数の値を同時に処理できます。 最後の summer (共有の合計を更新) は、共有値をロックしなくてもいいように、一度に 1 つの受け取ったタプルのみ処理します。
#include <cstdio>
#include "tbb/flow_graph.h"
using namespace tbb::flow;
struct square {
int operator()(int v) { return v*v; }
};
struct cube {
int operator()(int v) { return v*v*v; }
};
class sum {
int &my_sum;
public:
sum( int &s ) : my_sum(s) {}
int operator()( std::tuple< int, int > v ) {
my_sum += std::get<0>(v) + std::get<1>(v);
return my_sum;
}
};
int main() {
int result = 0;
graph g;
broadcast_node<int> input;
function_node<int,int> squarer( g, unlimited, square() );
function_node<int,int> cuber( g, unlimited, cube() );
join_node< std::tuple<int,int>, queueing > join( g );
function_node<std::tuple<int,int>,int>
summer( g, serial, sum(result) );
make_edge( input, squarer );
make_edge( input, cuber );
make_edge( squarer, std::get<0>( join.inputs() ) );
make_edge( cuber, std::get<1>( join.inputs() ) );
make_edge( join, summer );
for (int i = 1; i <= 10; ++i)
input.try_put(i);
g.wait_for_all();
printf("最終結果は %d\n", result);
return 0;
}
上記のサンプルコードで、square、cube、sum クラスは 3 つのユーザー定義操作を定義しています。 各クラスは function_node を作成するために使用されます。
main 関数で、フローグラフがセットアップされ、値 1-10 が input ノードに格納されます。 この例のノードはすべて、周囲に int 型の値オブジェクトを渡します。 この例で使用されているノードはすべてテンプレート・クラスであるため、ポインターとオブジェクトを含む、コピー構築をサポートするすべての型で使用できます。
値はノード間でコピーして渡されるため、大規模なオブジェクトの周囲で渡すとコピーのオーバーヘッドが発生します。 オーバーヘッドを回避するには、代わりにオブジェクトへのポインターを渡してください。
これは単純な構文の例にすぎません。フローグラフの各ノードは独立したタスクとして実行されるため、各ノードの粒度は、『インテル® スレッディング・ビルディング・ブロック (インテル® TBB) 入門チュートリアル』で説明されているタスクの一般的なガイドラインに従ってください。
この例で使用されているクラスと関数は、「フローグラフ」からリンクされているトピックで詳細に説明されています。