Intel® oneAPI Threading Building Blocks
Ask questions and share information about adding parallelism to your applications when using this threading library.

setting a composite node



I have done some experiment trying to adapt the flow graph to our objectives. I have had difficulties setting a composite node that basically links a join node with a multifunction node. I have ran that experiment:

  template< typename InputTuple, typename OutputTuple >
    class GraphNode : public tbb::flow::composite_node< InputTuple, OutputTuple >
        typedef tbb::flow::join_node< InputTuple, tbb::flow::queueing > join_node_type;
        typedef tbb::flow::multifunction_node< InputTuple, OutputTuple > multi_node_type;
        join_node_type  m_jnode;
        multi_node_type m_multinode;
        typedef tbb::flow::composite_node< InputTuple, OutputTuple > compo_node_type;

        typedef typename multi_node_type::output_ports_type output_ports_type;
        typedef std::function< void(const InputTuple&, output_ports_type&) > body_type;        
        GraphNode(tbb::flow::graph &g, const body_type &body)
        : compo_node_type(g), m_jnode(g), m_multinode(g, tbb::flow::unlimited, body)
            tbb::flow::make_edge(m_jnode, m_multinode);
            typename compo_node_type::input_ports_type input_tuple(tbb::flow::input_port<0>(m_jnode), tbb::flow::input_port<1>(m_jnode));
            typename compo_node_type::output_ports_type output_tuple(tbb::flow::output_port<0>(m_multinode));
            compo_node_type::set_external_ports(input_tuple, output_tuple);

void f1(const tbb::flow::tuple<msg_t, msg_t> &ip,
        GraphNode<tbb::flow::tuple<msg_t,msg_t>, tbb::flow::tuple<msg_t>>::output_ports_type &op)
    std::cout << "Running f1" << std::endl;

void f2(const tbb::flow::tuple<msg_t, msg_t> &ip,
        AWB::GraphNode<tbb::flow::tuple<msg_t,msg_t>, tbb::flow::tuple<msg_t>>::output_ports_type &op)
    std::cout << "Running f2" << std::endl;

int main() {
    graph g;
    GraphNode<tbb::flow::tuple<msg_t,msg_t>, tbb::flow::tuple<msg_t>> a0(g, f1), a1(g, f2);
    split_node< tuple<msg_t, msg_t, msg_t, msg_t> > s(g);

    make_edge(output_port<0>(s), input_port<0>(a0));
    make_edge(output_port<1>(s), input_port<1>(a0));

    make_edge(output_port<0>(a0), input_port<0>(a1));
    make_edge(output_port<2>(s), input_port<1>(a1));

    s.try_put(std::make_tuple(msg_t(), msg_t(), msg_t(), msg_t()));

    return 0;

But unfortunately it fails when I try to connect the output of a GraphNode with the input of another Graph node (l.52) with this message

tbb/include/tbb/internal/_flow_graph_node_impl.h:649:16: Non-const lvalue reference to type 'typename tbb::flow::tuple_element<0UL, typename GraphNode<tuple<continue_msg, continue_msg>, tuple<continue_msg> >::output_ports_type>::type' (aka '__type_pack_element<0UL, tbb::flow::interface10::internal::multifunction_output<tbb::flow::interface10::continue_msg> >') cannot bind to a value of unrelated type 'tbb::flow::interface10::sender<tbb::flow::interface10::continue_msg>'

I have spent hours trying to solve this problem without any success, can someone help me solving it please?

0 Kudos
1 Reply

A quick update to mention that thanks to Vasanth from Intel I have been able to track this issue. Changing line 13

typedef typename multi_node_type::output_ports_type output_ports_type;


typedef typename multi_node_type::output_ports_type out_ports_type;

fixed the compilation issue and everything worked as intended.


So I am so far able to build a composite node (join + multifunction) which basically waits on all its input ports before running its multi body and sending messages through its output ports.

Regarding the problem I am trying to tackle 2 questions are still opened:

- can this GraphNodes input and output port number be set dynamically (assuming that the type of these ports is a tuple<T, T, T, …> of different size for input and output, with basically T a continue_msg)? Apparently a solution is given here (l.526)

It consists in defining every multifunction_node types one would need (this code shows 10 possible options because there’s only 1 output port, 10*10 is what I am interested in), setting your inner multifunction_node as void* and then call a new on the type you want at runtime. 

Is someone aware of that kind of solution, is there other options to solve that problem of dynamically setting the port number of a multifunction_node?

- now I am able to create the nodes I need on the fly I would like to link them on the fly, for example being able to link the second output port of one node to the first input port of another node at runtime. The problem is that I strictly don’t know how to do it, if it’s possible or if there is any workaround?

Thanks for your help

0 Kudos