|
| 1 | +.. _try_put_and_wait: |
| 2 | + |
| 3 | +Waiting for Single Messages in Flow Graph |
| 4 | +========================================= |
| 5 | + |
| 6 | +.. contents:: |
| 7 | + :local: |
| 8 | + :depth: 1 |
| 9 | + |
| 10 | +Description |
| 11 | +*********** |
| 12 | + |
| 13 | +This feature adds a new ``try_put_and_wait`` interface to the receiving nodes in the Flow Graph. |
| 14 | +This function puts a message as an input into a Flow Graph and waits until all work related to |
| 15 | +that message is complete. |
| 16 | +``try_put_and_wait`` may reduce latency compared to calling ``graph::wait_for_all`` since |
| 17 | +``graph::wait_for_all`` waits for all work, including work that is unrelated to the input message, to complete. |
| 18 | + |
| 19 | +``node.try_put_and_wait(msg)`` performs ``node.try_put(msg)`` on the node and waits until the work on ``msg`` is completed. |
| 20 | +Therefore, the following conditions are true: |
| 21 | + |
| 22 | +* Any task initiated by any node in the Flow Graph that involves working with ``msg`` or any other intermediate result |
| 23 | + computed from ``msg`` is completed. |
| 24 | +* No intermediate results computed from ``msg`` remain in any buffers in the graph. |
| 25 | + |
| 26 | +.. caution:: |
| 27 | + |
| 28 | + To prevent ``try_put_and_wait`` calls from infinite waiting, avoid using buffering nodes at the end of the Flow Graph since the final result |
| 29 | + will not be automatically consumed by the Flow Graph. |
| 30 | + |
| 31 | +.. caution:: |
| 32 | + |
| 33 | + The ``multifunction_node`` and ``async_node`` classes are not currently supported by this feature. Including one of these nodes in the |
| 34 | + Flow Graph may cause ``try_put_and_wait`` to exit early, even if the computations on the initial input message are |
| 35 | + still in progress. |
| 36 | + |
| 37 | +API |
| 38 | +*** |
| 39 | + |
| 40 | +Header |
| 41 | +------ |
| 42 | + |
| 43 | +.. code:: cpp |
| 44 | +
|
| 45 | + #define TBB_PREVIEW_FLOW_GRAPH_FEATURES // macro option 1 |
| 46 | + #define TBB_PREVIEW_FLOW_GRAPH_TRY_PUT_AND_WAIT // macro option 2 |
| 47 | + #include <oneapi/tbb/flow_graph.h> |
| 48 | +
|
| 49 | +Synopsis |
| 50 | +-------- |
| 51 | + |
| 52 | +.. code:: cpp |
| 53 | +
|
| 54 | + namespace oneapi { |
| 55 | + namespace tbb { |
| 56 | + template <typename Output, typename Policy = /*default-policy*/> |
| 57 | + class continue_node { |
| 58 | + public: |
| 59 | + bool try_put_and_wait(const continue_msg& input); |
| 60 | + }; // class continue_node |
| 61 | +
|
| 62 | + template <typename Input, typename Output = continue_msg, typename Policy = /*default-policy*/> |
| 63 | + class function_node { |
| 64 | + public: |
| 65 | + bool try_put_and_wait(const Input& input); |
| 66 | + }; // class function_node |
| 67 | +
|
| 68 | + template <typename T> |
| 69 | + class overwrite_node { |
| 70 | + public: |
| 71 | + bool try_put_and_wait(const T& input); |
| 72 | + }; // class overwrite_node |
| 73 | +
|
| 74 | + template <typename T> |
| 75 | + class write_once_node { |
| 76 | + public: |
| 77 | + bool try_put_and_wait(const T& input); |
| 78 | + }; // class write_once_node |
| 79 | +
|
| 80 | + template <typename T> |
| 81 | + class buffer_node { |
| 82 | + public: |
| 83 | + bool try_put_and_wait(const T& input); |
| 84 | + }; // class buffer_node |
| 85 | +
|
| 86 | + template <typename T> |
| 87 | + class queue_node { |
| 88 | + public: |
| 89 | + bool try_put_and_wait(const T& input); |
| 90 | + }; // class queue_node |
| 91 | +
|
| 92 | + template <typename T, typename Compare = std::less<T>> |
| 93 | + class priority_queue_node { |
| 94 | + public: |
| 95 | + bool try_put_and_wait(const T& input); |
| 96 | + }; // class priority_queue_node |
| 97 | +
|
| 98 | + template <typename T> |
| 99 | + class sequencer_node { |
| 100 | + public: |
| 101 | + bool try_put_and_wait(const T& input); |
| 102 | + }; // class sequencer_node |
| 103 | +
|
| 104 | + template <typename T, typename DecrementType = continue_msg> |
| 105 | + class limiter_node { |
| 106 | + public: |
| 107 | + bool try_put_and_wait(const T& input); |
| 108 | + }; // class limiter_node |
| 109 | +
|
| 110 | + template <typename T> |
| 111 | + class broadcast_node { |
| 112 | + public: |
| 113 | + bool try_put_and_wait(const T& input); |
| 114 | + }; // class broadcast_node |
| 115 | +
|
| 116 | + template <typename TupleType> |
| 117 | + class split_node { |
| 118 | + public: |
| 119 | + bool try_put_and_wait(const TupleType& input); |
| 120 | + }; // class split_node |
| 121 | + } // namespace tbb |
| 122 | + } // namespace oneapi |
| 123 | +
|
| 124 | +Member Functions |
| 125 | +---------------- |
| 126 | + |
| 127 | +.. code:: cpp |
| 128 | +
|
| 129 | + template <typename Output, typename Policy> |
| 130 | + bool continue_node<Output, Policy>::try_put_and_wait(const continue_msg& input) |
| 131 | +
|
| 132 | +**Effects**: Increments the count of input signals received. If the incremented count is equal to the number |
| 133 | +of known predecessors, performs the ``body`` function object execution. |
| 134 | + |
| 135 | +Waits for the completion of the ``input`` in the Flow Graph, meaning all tasks created by each node and |
| 136 | +related to ``input`` are executed, and no related objects remain in any buffer within the graph. |
| 137 | + |
| 138 | +**Returns**: ``true``. |
| 139 | + |
| 140 | +.. code:: cpp |
| 141 | +
|
| 142 | + template <typename Input, typename Output, typename Policy> |
| 143 | + bool function_node<Input, Output, Policy>::try_put_and_wait(const Input& input) |
| 144 | +
|
| 145 | +**Effects**: If the concurrency limit allows, executes the user-provided body on the incoming message ``input``. |
| 146 | +Otherwise, depending on the ``Policy`` of the node, either queues the incoming message ``input`` or rejects it. |
| 147 | + |
| 148 | +Waits for the completion of the ``input`` in the Flow Graph, meaning all tasks created by each node and |
| 149 | +related to ``input`` are executed, and no related objects remain in any buffer within the graph. |
| 150 | + |
| 151 | +**Returns**: ``true`` if the input is accepted, ``false`` otherwise. |
| 152 | + |
| 153 | +.. code:: cpp |
| 154 | +
|
| 155 | + template <typename T> |
| 156 | + bool overwrite_node<T>::try_put_and_wait(const T& input) |
| 157 | +
|
| 158 | +**Effects**: Stores ``input`` in the internal single-item buffer and broadcasts it to all successors. |
| 159 | + |
| 160 | +Waits for the completion of the ``input`` in the Flow Graph, meaning all tasks created by each node and |
| 161 | +related to ``input`` are executed, and no related objects remain in any buffer within the graph. |
| 162 | + |
| 163 | +**Returns**: ``true``. |
| 164 | + |
| 165 | +.. caution:: |
| 166 | + |
| 167 | + Since the input element is not retrieved from ``overwrite_node`` once accepted by the successor, |
| 168 | + retrieve it by explicitly calling the ``clear()`` method or by overwriting with another element to prevent |
| 169 | + ``try_put_and_wait`` from indefinite waiting. |
| 170 | + |
| 171 | +.. code:: cpp |
| 172 | +
|
| 173 | + template <typename T> |
| 174 | + bool write_once_node<T>::try_put_and_wait(const T& input) |
| 175 | +
|
| 176 | +**Effects**: Stores ``input`` in the internal single-item buffer if it does not contain a valid value already. |
| 177 | +If a new value is set, the node broadcasts it to all successors. |
| 178 | + |
| 179 | +Waits for the completion of the ``input`` in the Flow Graph, meaning all tasks created by each node and |
| 180 | +related to ``input`` are executed, and no related objects remain in any buffer within the graph. |
| 181 | + |
| 182 | +**Returns**: ``true`` for the first time after construction or a call to ``clear()``. |
| 183 | + |
| 184 | +.. caution:: |
| 185 | + |
| 186 | + Since the input element is not retrieved from the ``write_once_node`` once accepted by the successor, |
| 187 | + retrieve it by explicitly calling the ``clear()`` method to prevent ``try_put_and_wait`` from indefinite waiting. |
| 188 | + |
| 189 | +.. code:: cpp |
| 190 | +
|
| 191 | + template <typename T> |
| 192 | + bool buffer_node<T>::try_put_and_wait(const T& input) |
| 193 | +
|
| 194 | +**Effects**: Adds ``input`` to the set of items managed by the node and tries forwarding it to a successor. |
| 195 | + |
| 196 | +Waits for the completion of the ``input`` in the Flow Graph, meaning all tasks created by each node and |
| 197 | +related to ``input`` are executed, and no related objects remain in any buffer within the graph. |
| 198 | + |
| 199 | +**Returns**: ``true``. |
| 200 | + |
| 201 | +.. code:: cpp |
| 202 | +
|
| 203 | + template <typename T> |
| 204 | + bool queue_node<T>::try_put_and_wait(const T& input) |
| 205 | +
|
| 206 | +**Effects**: Adds ``input`` to the set of items managed by the node and tries forwarding the least recently added item |
| 207 | +to a successor. |
| 208 | + |
| 209 | +Waits for the completion of the ``input`` in the Flow Graph, meaning all tasks created by each node and |
| 210 | +related to ``input`` are executed, and no related objects remain in any buffer within the graph. |
| 211 | + |
| 212 | +**Returns**: ``true``. |
| 213 | + |
| 214 | +.. code:: cpp |
| 215 | +
|
| 216 | + template <typename T, typename Compare> |
| 217 | + bool priority_queue_node<T>::try_put_and_wait(const T& input) |
| 218 | +
|
| 219 | +**Effects**: Adds ``input`` to the ``priority_queue_node`` and attempts to forward the item with the highest |
| 220 | +priority among all items added to the node but not yet forwarded to the successors. |
| 221 | + |
| 222 | +Waits for the completion of the ``input`` in the Flow Graph, meaning all tasks created by each node and |
| 223 | +related to ``input`` are executed, and no related objects remain in any buffer within the graph. |
| 224 | + |
| 225 | +**Returns**: ``true``. |
| 226 | + |
| 227 | +.. code:: cpp |
| 228 | +
|
| 229 | + template <typename T> |
| 230 | + bool sequencer_node<T>::try_put_and_wait(const T& input) |
| 231 | +
|
| 232 | +**Effects**: Adds ``input`` to the ``sequencer_node`` and tries forwarding the next item in sequence to a successor. |
| 233 | + |
| 234 | +Waits for the completion of the ``input`` in the Flow Graph, meaning all tasks created by each node and |
| 235 | +related to ``input`` are executed, and no related objects remain in any buffer within the graph. |
| 236 | + |
| 237 | +**Returns**: ``true``. |
| 238 | + |
| 239 | +.. code:: cpp |
| 240 | +
|
| 241 | + template <typename T, typename DecrementType> |
| 242 | + bool limiter_node<T, DecrementType>::try_put_and_wait(const T& input) |
| 243 | +
|
| 244 | +**Effects**: If the broadcast count is below the threshold, broadcasts ``input`` to all successors. |
| 245 | + |
| 246 | +Waits for the completion of the ``input`` in the Flow Graph, meaning all tasks created by each node and |
| 247 | +related to ``input`` are executed, and no related objects remain in any buffer within the graph. |
| 248 | + |
| 249 | +**Returns**: ``true`` if ``input`` is broadcasted; ``false`` otherwise. |
| 250 | + |
| 251 | +.. code:: cpp |
| 252 | +
|
| 253 | + template <typename T> |
| 254 | + bool broadcast_node<T>::try_put_and_wait(const T& input) |
| 255 | +
|
| 256 | +**Effects**: Broadcasts ``input`` to all successors. |
| 257 | + |
| 258 | +Waits for the completion of the ``input`` in the Flow Graph, meaning all tasks created by each node and |
| 259 | +related to ``input`` are executed, and no related objects remain in any buffer within the graph. |
| 260 | + |
| 261 | +**Returns**: ``true`` even if the node cannot successfully forward the message to any of its successors. |
| 262 | + |
| 263 | +.. code:: cpp |
| 264 | +
|
| 265 | + template <typename TupleType> |
| 266 | + bool split_node<TupleType>::try_put_and_wait(const TupleType& input); |
| 267 | +
|
| 268 | +**Effects**: Broadcasts each element in the incoming tuple to the nodes connected to the ``split_node`` output ports. |
| 269 | +The element at index ``i`` of ``input`` is broadcasted through the output port number ``i``. |
| 270 | + |
| 271 | +Waits for the completion of the ``input`` in the Flow Graph, meaning all tasks created by each node and |
| 272 | +related to ``input`` are executed, and no related objects remain in any buffer within the graph. |
| 273 | + |
| 274 | +**Returns**: ``true``. |
| 275 | + |
| 276 | +Example |
| 277 | +******* |
| 278 | + |
| 279 | +.. code:: cpp |
| 280 | +
|
| 281 | + #define TBB_PREVIEW_FLOW_GRAPH_TRY_PUT_AND_WAIT |
| 282 | + #include <oneapi/tbb/flow_graph.h> |
| 283 | + #include <oneapi/tbb/parallel_for.h> |
| 284 | +
|
| 285 | + struct f1_body; |
| 286 | + struct f2_body; |
| 287 | + struct f3_body; |
| 288 | + struct f4_body; |
| 289 | +
|
| 290 | + int main() { |
| 291 | + using namespace oneapi::tbb; |
| 292 | +
|
| 293 | + flow::graph g; |
| 294 | + flow::broadcast_node<int> start_node(g); |
| 295 | +
|
| 296 | + flow::function_node<int, int> f1(g, flow::unlimited, f1_body{}); |
| 297 | + flow::function_node<int, int> f2(g, flow::unlimited, f2_body{}); |
| 298 | + flow::function_node<int, int> f3(g, flow::unlimited, f3_body{}); |
| 299 | +
|
| 300 | + flow::join_node<std::tuple<int, int>> join(g); |
| 301 | +
|
| 302 | + flow::function_node<std::tuple<int, int>, int> f4(g, flow::serial, f4_body{}); |
| 303 | +
|
| 304 | + flow::make_edge(start_node, f1); |
| 305 | + flow::make_edge(f1, f2); |
| 306 | +
|
| 307 | + flow::make_edge(start_node, f3); |
| 308 | +
|
| 309 | + flow::make_edge(f2, flow::input_port<0>(join)); |
| 310 | + flow::make_edge(f3, flow::input_port<1>(join)); |
| 311 | +
|
| 312 | + flow::make_edge(join, f4); |
| 313 | +
|
| 314 | + // Submit work into the graph |
| 315 | + parallel_for(0, 100, [](int input) { |
| 316 | + start_node.try_put_and_wait(input); |
| 317 | +
|
| 318 | + // Post processing the result of input |
| 319 | + }); |
| 320 | + } |
| 321 | +
|
| 322 | +Each iteration of ``parallel_for`` submits an input into the Flow Graph. After returning from ``try_put_and_wait(input)``, it is |
| 323 | +guaranteed that all of the work related to the completion of ``input`` is done by all of the nodes in the graph. Tasks related to inputs |
| 324 | +submitted by other calls are not guaranteed to be completed. |
0 commit comments