1.. _broadcast_or_send:
2
3Sending to One or Multiple Successors
4=====================================
5
6
7An important characteristic of the predefined nodes is whether they push
8their output to a single successor or broadcast to all successors. The
9following predefined nodes push messages to a single successor:
10
11
12-  buffer_node
13-  queue_node
14-  priority_queue_node
15-  sequencer_node
16
17
18Other nodes push messages to all successors that will accept them.
19
20
21The nodes that push to only a single successor are all buffer nodes.
22Their purpose is to hold messages temporarily, until they are consumed
23downstream. Consider the example below:
24
25
26::
27
28
29   void use_buffer_and_two_nodes() {
30     graph g;
31
32
33     function_node< int, int, rejecting > f1( g, 1, []( int i ) -> int {
34       spin_for(0.1);
35       cout << "f1 consuming " << i << "\n";
36       return i;
37     } );
38
39
40     function_node< int, int, rejecting > f2( g, 1, []( int i ) -> int {
41       spin_for(0.2);
42       cout << "f2 consuming " << i << "\n";
43       return i;
44     } );
45
46
47     priority_queue_node< int > q(g);
48
49
50     make_edge( q, f1 );
51     make_edge( q, f2 );
52     for ( int i = 10; i > 0; --i ) {
53       q.try_put( i );
54     }
55     g.wait_for_all();
56   }
57
58
59First, function_nodes by default queue up the messages they receive at
60their input. To make a priority_queue_node work properly with a
61function_node, the example above constructs its function_nodes with its
62buffer policy set to rejecting. So, f1 and f2 do not internally buffer
63incoming messages, but instead rely on upstream buffering in the
64priority_queue_node.
65
66
67In the above example, each message buffered by the priority_queue_node
68is sent to either f1 or f2, but not both.
69
70
71Let's consider the alternative behavior; that is; what if the
72priority_queue_node broadcasts to all successors. What if some, but not
73all, nodes accept a message? Should the message be buffered until all
74nodes accept it, or be only delivered to the accepting subset? If the
75node continues to buffer the message, should it eventually deliver the
76messages in the same order to all nodes or in the current priority order
77at the time the node accepts the next message? For example, assume a
78priority_queue_node only contains "9" when a successor node, f1, accepts
79"9" but another successor node, f2, rejects it. Later a value "100"
80arrives and f2 is available to accept messages. Should f2 receive "9"
81next or "100", which has a higher priority? In any case, trying to
82ensure that all successors receive each message creates a garbage
83collection problem and complicates reasoning. Therefore, these buffering
84nodes push each message to only one successor. And, you can use this
85characteristic to create useful graph structures such as the one shown
86in the graph above, where each message will be processed in priority
87order, by either f1 or f2.
88
89
90But what if you really do want both f1 and f2 to receive all of the
91values, and in priority order? You can easily create this behavior by
92creating one priority_queue_node for each function_node, and pushing
93each value to both queues through a broadcast_node, as shown below:
94
95
96::
97
98
99     graph g;
100
101
102     function_node< int, int, rejecting > f1( g, 1, []( int i ) -> int {
103       spin_for(0.1);
104       cout << "f1 consuming " << i << "\n";
105       return i;
106     } );
107
108
109     function_node< int, int, rejecting > f2( g, 1, []( int i ) -> int {
110       spin_for(0.2);
111       cout << "f2 consuming " << i << "\n";
112       return i;
113     } );
114
115
116     priority_queue_node< int > q1(g);
117     priority_queue_node< int > q2(g);
118     broadcast_node< int > b(g);
119
120
121     make_edge( b, q1 );
122     make_edge( b, q2 );
123     make_edge( q1, f1 );
124     make_edge( q2, f2 );
125     for ( int i = 10; i > 0; --i ) {
126       b.try_put( i );
127     }
128     g.wait_for_all();
129
130
131So, when connecting a node in your graph to multiple successors, be sure
132to understand whether the output will broadcast to all of the
133successors, or just a single successor.
134
135