グラフ間の通信

グラフノードはすべて、コンストラクターの引数の 1 つとしてグラフ・オブジェクトへの参照が必要です。同じグラフの一部であるノード間のエッジを構築する場合のみ安全です。エッジは、ランタイム・ライブラリーに対するグラフのトポロジーを表現します。異なるグラフの 2 つのノードを接続すると、graph::wait_for_all の呼び出しや例外処理のようなグラフ全体の操作を理解することが困難になります。パフォーマンスを最適化するため、ライブラリーは、ユーザーが予期していないときにノードのプレデセッサーまたはサクセサーを呼び出すことがあります。

2 つのグラフを接続しなければならない場合は、それらのグラフ間にエッジを作成せず、代わりに try_put の明示的な呼び出しを使用します。ランタイム・ライブラリーが 2 つのノード間の関係を仮定する必要がなくなるため、グラフ境界を超えるイベントを理解しやすくなります。しかし、グラフ全体の操作を理解することはまだ困難です。例えば、次のグラフについて考えてみます。

    graph g;
    function_node< int, int > n1( g, 1, [](int i) -> int { 
        cout << "n1\n"; 
        spin_for(i); 
        return i; 
    } );
    function_node< int, int > n2( g, 1, [](int i) -> int { 
        cout << "n2\n"; 
        spin_for(i); 
        return i; 
    } );
    make_edge( n1, n2 );

    graph g2;
    function_node< int, int > m1( g2, 1, [](int i) -> int { 
        cout << "m1\n"; 
        spin_for(i); 
        return i; 
    } );
    function_node< int, int > m2( g2, 1, [&](int i) -> int { 
        cout << "m2\n"; 
        spin_for(i); 
        n1.try_put(i); 
        return i; 
    } );
    make_edge( m1, m2 );

    m1.try_put( 1 );

    // 次の呼び出しは直ちにリターン
    g.wait_for_all();
    // 次の呼び出しは m1 と m2 の後にリターン
    g2.wait_for_all();

    // wait_for_all が両方のグラフで呼ばれたとしても
    // n1 と n2 が完了する前にここに達する

上記の例で、m1.try_put(1) はノード m1 にメッセージを送ります。ノード m1 はボディーを実行し、ノード m2 にメッセージを送ります。次に、ノード m2 はボディーを実行し、明示的な try_put を使用して n1 にメッセージを送ります。次に、n1 はボディーを実行し、n2 にメッセージを送ります。エッジが存在しないため、ランタイム・ライブラリーは m2n1 のプレデセッサーであると見なしません。

これらのグラフによってスポーンされたタスクがすべて完了するまで待つ場合は、両方のグラフで wait_for_all 関数を呼び出す必要があります。ただし、グラフ間の通信があるため、呼び出しの順序が重要です。上記の (正しくない) コードセグメントでは、g でアクティブなタスクがないため g.wait_for_all() の呼び出しは直ちにリターンし、スポーンしていたタスクのみ g2 に属します。m1m2g2 に属するため、g2.wait_for_all の呼び出しは m1 と m2 の両方が完了した後にリターンします。しかし、n1n2g に属するため、この呼び出しは n1 と n2 を待機しません。このため、n1n2 が完了する前に、このコードセグメントの最後に達します。

wait_for_all の呼び出しがスワップされると、コードは予想したとおりに動作します。

    g2.wait_for_all();
    g.wait_for_all();

    // すべてのタスクが完了

これらの小さな 2 つのグラフがどのように対話するかを理解することはそれほど困難ではありませんが、複数のサイクルを含む大きな 2 つのグラフの場合は困難でしょう。このため、異なるグラフのノード間の通信は注意して行う必要があります。

関連情報