1

With TBB you can make a nice DAG of tasks and it can automatically run them in parallel. Example from the documentation:

typedef continue_node< continue_msg > node_t;
typedef const continue_msg & msg_t;

int main() {
  tbb::flow::graph g;
  node_t A(g, [](msg_t){ a(); } );
  node_t B(g, [](msg_t){ b(); } );
  node_t C(g, [](msg_t){ c(); } );
  node_t D(g, [](msg_t){ d(); } );
  node_t E(g, [](msg_t){ e(); } );
  node_t F(g, [](msg_t){ f(); } );
  make_edge(A, B);
  make_edge(B, C);
  make_edge(B, D);
  make_edge(A, E);
  make_edge(E, D);
  make_edge(E, F);
  A.try_put( continue_msg() );
  g.wait_for_all();
  return 0;
}

That works fine, however it assumes I have some well-known root node and all nodes are dependants of that node. What if I have some more generic network that might have multiple root nodes?

int main() {
  tbb::flow::graph g;

  // Imagine a function did this but in a generic way:      
  node_t A(g, [](msg_t){ a(); } );
  node_t B(g, [](msg_t){ b(); } );
  node_t C(g, [](msg_t){ c(); } );
  node_t D(g, [](msg_t){ d(); } );
  node_t E(g, [](msg_t){ e(); } );
  node_t F(g, [](msg_t){ f(); } );
  make_edge(A, B);
  make_edge(B, C);
  make_edge(D, E);

  // Now how do I now do this?
  A.try_put( continue_msg() );
  D.try_put( continue_msg() );
  F.try_put( continue_msg() );

  g.wait_for_all();
  return 0;
}

I hope that example is clear - basically I have a load of tasks, but the dependencies between them are dynamic so they might end up not depending on each other at all. How do I say to TBB: "Ok I want all these tasks run."

(Obviously I can manually count the number of dependencies for each task but I'm asking if TBB does that already.)

Edit: To be clear I'm asking if there is a function that automatically starts all the root nodes. Obviously I can do it manually - that's what the example above does!

Timmmm
  • 88,195
  • 71
  • 364
  • 509
  • There is no problem with several "root nodes" since they are all equal and the task is created and run for each `try_put` calls, even though `g.wait_for_all` haven't yet executed. The `graph` object handles the references for all nodes. So, when all nodes are processed and there is no work in the graph, `wait_for_all()` serves as a synchronization point and will return. You can even make new edges during the graph processing. – Nikita Ponomarev Dec 14 '18 at 18:02
  • Yes I know. My question is not "how can I start multiple root nodes" it is "is there a function to *automatically* find all the root nodes and start them". – Timmmm Dec 15 '18 at 17:49
  • 1
    Then, unfortunately, there is no such built-in functionality in the Flow Graph. – Nikita Ponomarev Dec 17 '18 at 09:49

1 Answers1

0

This is probably a misunderstanding about flow::graph itself. You must specify dependencies programmatically by adding arcs between nodes. You try_put to the first node of the graph to start it. This is the only way to start a graph.

If you have external events that you want to trigger a graph to run, you must create a listener to that event which try_puts to start the graph.

You can create a multifunction_node that never returns, which you can have looking for events and sending messages, but this is poor TBB design. You would be permanently locking a TBB task to that multifunction_node, a no-no. And you still have to try_put something to the multifunction_node to start it.

cahuson
  • 826
  • 4
  • 10
  • I think you misunderstood my question. I want a function that *automatically* finds `A`, `D`, and `F` and starts them. – Timmmm Dec 15 '18 at 17:48