oneTBB quickstart
Purpose
Parallelizes C++ loops and reductions with Intel oneAPI Threading Building Blocks
on Intel CPUs: the umbrella header, parallel_for and parallel_reduce over a
blocked_range, the CMake lines that link it, and the assumptions the task-based
model breaks.
Prefer oneTBB over hand-rolled threads when the work is a bounded loop or a
reduction over a container: the partitioner decides the split, and the runtime
composes with other oneTBB-based libraries in the same process instead of
oversubscribing the machine.
When to Use This Skill
Use this skill when:
- A C++ loop or reduction is a candidate for multithreading.
- A first oneTBB program needs headers, namespace, and CMake wiring.
- A
parallel_for body has a race on shared state.
- A reduction accumulates into one variable from many threads.
Do not use this skill for GPU offload, for OpenMP or std::thread questions,
or for tuning an existing oneTBB program's grain size and partitioners — that is
past "getting started" and belongs with a profile in hand.
Quick Start
#include <oneapi/tbb.h> // umbrella header
int main() {
oneapi::tbb::parallel_for(
oneapi::tbb::blocked_range<size_t>(0, n),
[&](const oneapi::tbb::blocked_range<size_t>& r) {
for (size_t i = r.begin(); i != r.end(); ++i)
out[i] = f(in[i]);
});
}
using namespace oneapi::tbb; shortens the calls; qualifying them keeps the
origin visible in code that mixes threading libraries.
Implementation Guide
Parallelize a loop with parallel_for over a range. The body receives a
subrange, not a single index — iterate inside it, as above. The range type
carries the index type, so blocked_range<size_t> and blocked_range<int>
are different instantiations.
Reduce with parallel_reduce, not a shared accumulator. The body folds a
subrange into a partial result and the last argument combines two partials:
double sum = oneapi::tbb::parallel_reduce(
oneapi::tbb::blocked_range<size_t>(0, n), 0.0,
[&](const auto& r, double acc) {
for (size_t i = r.begin(); i != r.end(); ++i) acc += a[i];
return acc;
},
std::plus<double>());
Link it in CMake. oneTBB ships a package config, so the two lines are the
whole build change:
find_package(TBB REQUIRED)
target_link_libraries(my_app PRIVATE TBB::tbb)
Leave the grain size alone at first. The auto-partitioner chooses the
split; a hand-set grain size is a tuning decision that needs a measurement
behind it, and a wrong one is worse than none.
Make shared state safe or remove it. If the body must write to a shared
structure, use one of the concurrent_* containers or restructure as a
reduction. A mutex around the body of a parallel_for usually gives back the
parallelism it was added to protect.
Performance
No measured numbers ship with this skill, and a parallel version is not
automatically a faster one. What to measure:
- Compare against the serial loop on the same input, with the same compiler flags
and optimization level.
- Watch for a body too small to cover the task overhead: at that size the
partitioner's fixed cost shows up as a slowdown.
- Check whether the loop is memory-bandwidth bound before adding threads — more
threads on a saturated bus do not help.
- Count the threads in the process. Nested parallelism from another library, or
an OpenMP region around a oneTBB call, oversubscribes the cores and the
slowdown is not in either loop.
Gotchas & Limitations
- The body runs many times, concurrently. It is not called once per loop and
not once per thread; the range is split as the runtime sees fit. Anything
captured by reference and written to is shared mutable state.
parallel_reduce is not deterministic in floating point. The combination
order varies between runs, so sums can differ in the last bits. Use
parallel_deterministic_reduce when a reproducible result matters more than
speed.
- Exceptions propagate out of the algorithm, not out of the body where they
were thrown — one is rethrown on the caller's thread and the rest are lost.
find_package(TBB) needs oneTBB's own config, which the environment script
or the package install puts on CMAKE_PREFIX_PATH. A build that cannot find it
usually has not sourced the environment.
- Not covered: flow graph, task groups, arenas and thread affinity, and the
deprecated
tbb:: (pre-oneAPI) spellings.
References
| File |
Load it when |
references/official-sources.md |
you need the current oneTBB API for an algorithm, the deprecation status of a tbb:: name, or the supported CMake integration for the installed version |
Two things here should not be answered from memory: the current name and
signature of an algorithm (oneTBB renamed and dropped parts of the pre-oneAPI
API, and the old spellings still compile in some builds) and how the package is
found by CMake in the installed layout.
1---2name: onetbb-quickstart3description: Getting started with Intel oneTBB for C++ parallelism on Intel CPUs. Use when a C++ loop or reduction should run on multiple threads with oneTBB, when the user needs the headers, namespace, or CMake wiring for a first oneTBB program, when a parallel_for body has a data race, or when a reduction is accumulating into a shared variable. Covers parallel_for and parallel_reduce over blocked_range, the build setup, and the pitfalls of the task-based model.4license: Apache-2.05---67# oneTBB quickstart89## Purpose1011Parallelizes C++ loops and reductions with Intel oneAPI Threading Building Blocks12on Intel CPUs: the umbrella header, `parallel_for` and `parallel_reduce` over a13`blocked_range`, the CMake lines that link it, and the assumptions the task-based14model breaks.1516Prefer oneTBB over hand-rolled threads when the work is a bounded loop or a17reduction over a container: the partitioner decides the split, and the runtime18composes with other oneTBB-based libraries in the same process instead of19oversubscribing the machine.2021## When to Use This Skill2223Use this skill when:2425- A C++ loop or reduction is a candidate for multithreading.26- A first oneTBB program needs headers, namespace, and CMake wiring.27- A `parallel_for` body has a race on shared state.28- A reduction accumulates into one variable from many threads.2930Do **not** use this skill for GPU offload, for OpenMP or `std::thread` questions,31or for tuning an existing oneTBB program's grain size and partitioners — that is32past "getting started" and belongs with a profile in hand.3334## Quick Start3536```cpp37#include <oneapi/tbb.h> // umbrella header3839int main() {40 oneapi::tbb::parallel_for(41 oneapi::tbb::blocked_range<size_t>(0, n),42 [&](const oneapi::tbb::blocked_range<size_t>& r) {43 for (size_t i = r.begin(); i != r.end(); ++i)44 out[i] = f(in[i]);45 });46}47```4849`using namespace oneapi::tbb;` shortens the calls; qualifying them keeps the50origin visible in code that mixes threading libraries.5152## Implementation Guide53541. **Parallelize a loop with `parallel_for` over a range.** The body receives a55 subrange, not a single index — iterate inside it, as above. The range type56 carries the index type, so `blocked_range<size_t>` and `blocked_range<int>`57 are different instantiations.58592. **Reduce with `parallel_reduce`, not a shared accumulator.** The body folds a60 subrange into a partial result and the last argument combines two partials:6162 ```cpp63 double sum = oneapi::tbb::parallel_reduce(64 oneapi::tbb::blocked_range<size_t>(0, n), 0.0,65 [&](const auto& r, double acc) {66 for (size_t i = r.begin(); i != r.end(); ++i) acc += a[i];67 return acc;68 },69 std::plus<double>());70 ```71723. **Link it in CMake.** oneTBB ships a package config, so the two lines are the73 whole build change:7475 ```cmake76 find_package(TBB REQUIRED)77 target_link_libraries(my_app PRIVATE TBB::tbb)78 ```79804. **Leave the grain size alone at first.** The auto-partitioner chooses the81 split; a hand-set grain size is a tuning decision that needs a measurement82 behind it, and a wrong one is worse than none.83845. **Make shared state safe or remove it.** If the body must write to a shared85 structure, use one of the `concurrent_*` containers or restructure as a86 reduction. A mutex around the body of a `parallel_for` usually gives back the87 parallelism it was added to protect.8889## Performance9091No measured numbers ship with this skill, and a parallel version is not92automatically a faster one. What to measure:9394- Compare against the serial loop on the same input, with the same compiler flags95 and optimization level.96- Watch for a body too small to cover the task overhead: at that size the97 partitioner's fixed cost shows up as a slowdown.98- Check whether the loop is memory-bandwidth bound before adding threads — more99 threads on a saturated bus do not help.100- Count the threads in the process. Nested parallelism from another library, or101 an OpenMP region around a oneTBB call, oversubscribes the cores and the102 slowdown is not in either loop.103104## Gotchas & Limitations105106- **The body runs many times, concurrently.** It is not called once per loop and107 not once per thread; the range is split as the runtime sees fit. Anything108 captured by reference and written to is shared mutable state.109- **`parallel_reduce` is not deterministic in floating point.** The combination110 order varies between runs, so sums can differ in the last bits. Use111 `parallel_deterministic_reduce` when a reproducible result matters more than112 speed.113- **Exceptions propagate out of the algorithm**, not out of the body where they114 were thrown — one is rethrown on the caller's thread and the rest are lost.115- **`find_package(TBB)` needs oneTBB's own config**, which the environment script116 or the package install puts on `CMAKE_PREFIX_PATH`. A build that cannot find it117 usually has not sourced the environment.118- Not covered: flow graph, task groups, arenas and thread affinity, and the119 deprecated `tbb::` (pre-oneAPI) spellings.120121## References122123| File | Load it when |124|---|---|125| [`references/official-sources.md`](references/official-sources.md) | you need the current oneTBB API for an algorithm, the deprecation status of a `tbb::` name, or the supported CMake integration for the installed version |126127Two things here should not be answered from memory: **the current name and128signature of an algorithm** (oneTBB renamed and dropped parts of the pre-oneAPI129API, and the old spellings still compile in some builds) and **how the package is130found by CMake in the installed layout**.