oneTBB quickstart
SkillDev toolsGetting 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.
Available today. Use it from your connected AI after setup.
No other account needed.
Add ahel to your AI once: Claude, ChatGPT, Cursor, Claude Code or Codex. Then ask it to use this.
Then ask your AI: use the oneTBB quickstart skill
What this skill tells your AI
The instructions your AI receives, as published by intel/skills in skills/onetbb-quickstart/SKILL.md and read by ahel’s review.
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_forbody 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_forover a range. The body receives a subrange, not a single index — iterate inside it, as above. The range type carries the index type, soblocked_range<size_t>andblocked_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 aparallel_forusually 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_reduceis not deterministic in floating point. The combination order varies between runs, so sums can differ in the last bits. Useparallel_deterministic_reducewhen 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 onCMAKE_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.
Signals
- GitHub stars
- 21
- Forks
- 9
- Last commit
- Sep 2026
Advanced
- Item type
- skill
- Key
onetbb-quickstart- Source
- github.com/intel/skills