dwww Home | Show directory contents | Find package

.. _broadcast_or_send:

Sending to One or Multiple Successors
=====================================


An important characteristic of the predefined nodes is whether they push
their output to a single successor or broadcast to all successors. The
following predefined nodes push messages to a single successor:


-  buffer_node
-  queue_node
-  priority_queue_node
-  sequencer_node


Other nodes push messages to all successors that will accept them.


The nodes that push to only a single successor are all buffer nodes.
Their purpose is to hold messages temporarily, until they are consumed
downstream. Consider the example below:


::


   void use_buffer_and_two_nodes() {
     graph g;


     function_node< int, int, rejecting > f1( g, 1, []( int i ) -> int {
       spin_for(0.1);
       cout << "f1 consuming " << i << "\n";
       return i; 
     } );


     function_node< int, int, rejecting > f2( g, 1, []( int i ) -> int {
       spin_for(0.2);
       cout << "f2 consuming " << i << "\n";
       return i; 
     } );


     priority_queue_node< int > q(g);


     make_edge( q, f1 );
     make_edge( q, f2 );
     for ( int i = 10; i > 0; --i ) {
       q.try_put( i );
     }
     g.wait_for_all();
   }


First, function_nodes by default queue up the messages they receive at
their input. To make a priority_queue_node work properly with a
function_node, the example above constructs its function_nodes with its
buffer policy set to rejecting. So, f1 and f2 do not internally buffer
incoming messages, but instead rely on upstream buffering in the
priority_queue_node.


In the above example, each message buffered by the priority_queue_node
is sent to either f1 or f2, but not both.


Let's consider the alternative behavior; that is; what if the
priority_queue_node broadcasts to all successors. What if some, but not
all, nodes accept a message? Should the message be buffered until all
nodes accept it, or be only delivered to the accepting subset? If the
node continues to buffer the message, should it eventually deliver the
messages in the same order to all nodes or in the current priority order
at the time the node accepts the next message? For example, assume a
priority_queue_node only contains "9" when a successor node, f1, accepts
"9" but another successor node, f2, rejects it. Later a value "100"
arrives and f2 is available to accept messages. Should f2 receive "9"
next or "100", which has a higher priority? In any case, trying to
ensure that all successors receive each message creates a garbage
collection problem and complicates reasoning. Therefore, these buffering
nodes push each message to only one successor. And, you can use this
characteristic to create useful graph structures such as the one shown
in the graph above, where each message will be processed in priority
order, by either f1 or f2.


But what if you really do want both f1 and f2 to receive all of the
values, and in priority order? You can easily create this behavior by
creating one priority_queue_node for each function_node, and pushing
each value to both queues through a broadcast_node, as shown below:


::


     graph g;


     function_node< int, int, rejecting > f1( g, 1, []( int i ) -> int {
       spin_for(0.1);
       cout << "f1 consuming " << i << "\n";
       return i; 
     } );


     function_node< int, int, rejecting > f2( g, 1, []( int i ) -> int {
       spin_for(0.2);
       cout << "f2 consuming " << i << "\n";
       return i; 
     } );


     priority_queue_node< int > q1(g);
     priority_queue_node< int > q2(g);
     broadcast_node< int > b(g);


     make_edge( b, q1 );
     make_edge( b, q2 );
     make_edge( q1, f1 );
     make_edge( q2, f2 );
     for ( int i = 10; i > 0; --i ) {
       b.try_put( i );
     }
     g.wait_for_all();


So, when connecting a node in your graph to multiple successors, be sure
to understand whether the output will broadcast to all of the
successors, or just a single successor.

Generated by dwww version 1.15 on Thu May 23 06:42:50 CEST 2024.