Skip to content

Commit af8d95c

Browse files
authored
Add try_put_and_wait documentation (#1514)
1 parent 2a7e0db commit af8d95c

File tree

2 files changed

+325
-0
lines changed

2 files changed

+325
-0
lines changed

doc/main/reference/reference.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,3 +50,4 @@ The key properties of a preview feature are:
5050
concurrent_lru_cache_cls
5151
task_group_extensions
5252
custom_mutex_chmap
53+
try_put_and_wait
Lines changed: 324 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,324 @@
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

Comments
 (0)