input_node の使用#
デフォルトでは、input_node はアクティブではない状態で構築されます。
template< typename Body > input_node( graph &g, Body body, bool is_active=true )非アクティブな input_node をアクティブにするには、ノードの関数 activate を呼び出します。
input_node< int > src( g, src_body(10), false );
// make_edge の呼び出しで使用…
src.activate();すべての input_node オブジェクトは非アクティブな状態で構築され、通常はフローグラフ全体が構築された後にアクティブ化されます。
例えば、データ・フロー・グラフのコードを使用できます。この実装では、input_node は非アクティブな状態で構築され、他のすべてのエッジが作成された後にアクティブ化されます。
make_edge( squarer, summer );
make_edge( cuber, summer );
input_node< int > src( g, src_body(10), false );
make_edge( src, squarer );
make_edge( src, cuber );
src.activate();
g.wait_for_all();この例では、input_node が最初にアクティブ状態に切り替えられると、squarer へのエッジが接続された直後に squarer にメッセージが送信される可能性があります。その後、cuber へのエッジが接続されると、cuber は以降すべてのメッセージを受信しますが、すでにいくつかを見逃している可能性があります。
通常、input_node オブジェクトを非アクティブ状態で作成し、グラフ全体が構築された後にアクティブ化するのが最も安全です。ただし、このアプローチでは、グラフの構築とグラフの実行がシリアル化されます。
一部のグラフは、input_node をアクティブにして構築と実行のオーバーラップを許可して安全に構築できます。グラフが有向非巡回グラフ (DAG) であり、各 input_node に後続ノードが 1 つしかない場合、エッジを逆位相の順序で構築すると、構築直後に input_node をアクティブにできます。つまり、最初にツリー内の最も深いエッジを作成し、最も浅いエッジに戻って作業します。例えば、src が input_node であり、func1 と func2 が両方とも関数ノードである場合、次のグラフでは、src が構築直後にアクティブ化されてもメッセージは失われません。
const int limit = 10;
int count = 0;
graph g;
oneapi::tbb::flow::graph g;
oneapi::tbb::flow::input_node<int> src( g, [&]( oneapi::tbb::flow_control &fc ) -> int {
if ( count < limit ) {
return ++count;
}
fc.stop();
return {};
});
src.activate();
oneapi::tbb::flow::function_node<int,int> func1( g, 1, []( int i ) -> int {
std::cout << i << "\n";
return i;
} );
oneapi::tbb::flow::function_node<int,int> func2( g, 1, []( int i ) -> int {
std::cout << i << "\n";
return i;
} );
make_edge( func1, func2 );
make_edge( src, func1 );
g.wait_for_all();上記のコードは、func1 から func2 へのエッジが src から func1 へのエッジの前に作成されるため安全です。src から func1 へのエッジが最初に作成されると、func2 が接続される前に func1 がメッセージを生成する可能性があり、そのメッセージは失われます。また、 src には後継ノードが 1 つだけあります。src に複数の後続ノードがある場合、最初に接続した後続ノードは、その後に接続される後続ノードに届かないメッセージを受信する可能性があります。