Skip to content
Merged
Show file tree
Hide file tree
Changes from 12 commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
4566c85
Add task documentation to user guide
vossmjp Jul 25, 2025
4de1059
Added more details about task_group::wait thread safety
vossmjp Sep 12, 2025
d1d766d
Update doc/main/tbb_userguide/Parallelizing_with_Tasks.rst
vossmjp Sep 12, 2025
d3f8cd3
Fixed copyright
vossmjp Sep 12, 2025
f5b21a7
Update doc/main/tbb_userguide/examples/task_examples.cpp
vossmjp Sep 15, 2025
2f55a41
Update doc/main/tbb_userguide/examples/task_examples.cpp
vossmjp Sep 15, 2025
5a0f134
Addressed review comments
vossmjp Sep 15, 2025
c7ea938
Update doc/main/tbb_userguide/task_group_cancellation.rst
vossmjp Sep 16, 2025
a592315
Update doc/main/tbb_userguide/creating_tasks_with_task_group.rst
vossmjp Sep 16, 2025
668a17f
Update doc/main/tbb_userguide/task_group_thread_safety.rst
vossmjp Sep 16, 2025
bbc34f6
Update doc/main/tbb_userguide/task_group_thread_safety.rst
vossmjp Sep 16, 2025
0430818
Replaced CAS with comment
vossmjp Sep 16, 2025
335c02b
Simplified example
vossmjp Sep 19, 2025
634bba6
Modified other example to match simplification
vossmjp Sep 19, 2025
f33559a
Moved cancellation and shortened examples by ref
vossmjp Oct 3, 2025
f86c388
Update doc/main/tbb_userguide/examples/task_examples.cpp
vossmjp Oct 16, 2025
16a6423
Update doc/main/tbb_userguide/creating_tasks_with_task_group.rst
vossmjp Oct 16, 2025
b3f7578
Update doc/main/tbb_userguide/creating_tasks_with_task_group.rst
vossmjp Oct 16, 2025
030f7f0
Update doc/main/tbb_userguide/task_group_thread_safety.rst
vossmjp Oct 16, 2025
9ec8adc
Apply suggestion from @akukanov
vossmjp Oct 16, 2025
e1492fb
Updated cancellation to use task_group functions directly
vossmjp Oct 17, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
18 changes: 18 additions & 0 deletions doc/main/tbb_userguide/Parallelizing_with_Tasks.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
.. _Parallelizing_with_Tasks:

Parallelizing with Tasks
========================

When parallel loops or the flow graph are not sufficient, the |full_name|
library supports parallelization directly with tasks. Tasks
can be created using the function ``oneapi::tbb::parallel_invoke`` or
the class ``oneapi::tbb::task_group``.


.. toctree::
:maxdepth: 4

../tbb_userguide/creating_tasks_with_parallel_invoke
../tbb_userguide/creating_tasks_with_task_group
../tbb_userguide/task_group_cancellation
../tbb_userguide/task_group_thread_safety
55 changes: 55 additions & 0 deletions doc/main/tbb_userguide/creating_tasks_with_parallel_invoke.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
.. _creating_tasks_with_parallel_invoke:

Creating Tasks with parallel_invoke
===================================

Suppose you want to search a binary tree for the node that contains a specific value.
Here is sequential code to do this:

Nodes are represented by ``struct TreeNode``.

.. literalinclude:: ./examples/task_examples.cpp
:language: c++
:start-after: /*begin_treenode*/
:end-before: /*end_treenode*/

The function ``serial_tree_search`` is a recursive algorithm that checks the current node
and, if the value is not found, calls itself on the left and right subtree.

.. literalinclude:: ./examples/task_examples.cpp
:language: c++
:start-after: /*begin_search_serial*/
:end-before: /*end_search_serial*/


To improve performance, you can use ``oneapi::tbb::parallel_invoke`` to search the tree
in parallel:

A recursive base case is used after a minimum size threshold is reached to avoid parallel overheads.
Since more than one thread can call the base case concurrently as part of the same tree, ``result``
is held in an atomic variable.

.. literalinclude:: ./examples/task_examples.cpp
:language: c++
:start-after: /*begin_sequential_tree_search*/
:end-before: /*end_sequential_tree_search*/

The function ``oneapi::tbb::parallel_invoke`` runs multiple independent tasks in parallel.
Here is a function ``parallel_invoke_search``, where two lambdas are passed that define tasks
that search the left and right subtrees of the current node in parallel:

.. literalinclude:: ./examples/task_examples.cpp
:language: c++
:start-after: /*begin_parallel_invoke_search*/
:end-before: /*end_parallel_invoke_search*/

If the value is found the pointer to the node that contains the value is stored
in the ``std::atomic<TreeNode*> result``. This example uses recursion to create many tasks, instead of
just two. The depth of the parallel recursion is limited by the ``depth_threshold`` parameter. After this depth is
reached, the search falls back to a sequential approach. The value of ``result`` is periodically checked
to see if the value has been found by other concurrent tasks, and if so, the search in the current task is
terminated. Because multiple threads may access ``result`` concurrently, an atomic variable is used, even
from the sequential base case.

Because ``oneapi::tbb::parallel_invoke`` is a fork-join algorithm, each level of the recursion does not
complete until both the left and right subtrees have completed.
51 changes: 51 additions & 0 deletions doc/main/tbb_userguide/creating_tasks_with_task_group.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
.. _creating_tasks_with_task_group:

Creating Tasks with task_group
==============================

The |full_name| library supports parallelization directly with tasks. The class
``oneapi::tbb::task_group`` is used to run and wait for tasks in a less
structured way than ``oneapi::tbb::parallel_invoke``. It is useful when you want to
create a set of tasks that can be run in parallel, but you do not know how many there
will be in advance.

Here is code that uses ``oneapi::tbb::task_group`` to implement a parallel search in
a binary tree:

Nodes are represented by ``struct TreeNode``.

.. literalinclude:: ./examples/task_examples.cpp
:language: c++
:start-after: /*begin_treenode*/
:end-before: /*end_treenode*/

A recursive base case is used after a minimum size threshold is reached to avoid parallel overheads.
Since more than one thread can call the base case concurrently as part of the same tree, ``result``
is held in an atomic variable.

.. literalinclude:: ./examples/task_examples.cpp
:language: c++
:start-after: /*begin_sequential_tree_search*/
:end-before: /*end_sequential_tree_search*/

In ``parallel_tree_search_impl``, ``task_group::run`` is used to create a new task for searching
in the right subtree if both subtrees are valid. The recursion does not wait on the ``task_group``
at each level and reuses the current task to search one of the subtrees. This can reduce the
overhead of task creation and management, allowing for efficient use of resources.

.. literalinclude:: ./examples/task_examples.cpp
:language: c++
:start-after: /*begin_parallel_search*/
:end-before: /*end_parallel_search*/

This example uses recursion to create many tasks. The depth of the parallel recursion is
limited by the ``depth_threshold`` parameter. After this depth is reached, no new tasks
are created. The value of ``result`` is periodically checked to see if the value has been
found by other concurrent tasks, and if so, the search in the current task is terminated.

In this example, tasks that execute within the ``task_group tg`` add additional tasks
by calling ``run`` on the same ``task_group`` object. These calls are thread-safe and the
call to ``tg.wait()`` will block until all of these tasks are complete. Although these
additional tasks might be added from different worker threads, these additions are logically nested
within the top-most calls to ``tg.run``. There is therefore no race in adding these tasks from
the worker threads and waiting for them in the main thread.
Loading