TBB (Intel Threading Building Blocks) для C++: полное руководство с примерами

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс
TBB (Intel Threading Building Blocks) C++: методы, примеры, установка | PythonLib

📘 TBB (Intel Threading Building Blocks) для C++: полное руководство

oneAPI Threading Building Blocks (oneTBB) — это кроссплатформенная библиотека на языке C++, разработанная Intel для упрощения параллельного программирования. Она предоставляет высокоуровневые абстракции, которые позволяют разработчикам эффективно использовать многоядерные процессоры, не погружаясь в низкоуровневые детали работы с потоками, синхронизацией и планированием задач.

Зачем нужна TBB? В современном мире производительность процессоров растёт не за счёт увеличения тактовой частоты, а за счёт увеличения количества ядер. Чтобы программа работала быстрее на многоядерном процессоре, её необходимо распараллелить. Ручное управление потоками (через std::thread) сложно, чревато ошибками (гонки данных, взаимные блокировки) и плохо масштабируется. TBB решает эти проблемы, предлагая:

  • Автоматическое планирование задач — библиотека сама распределяет работу по доступным ядрам, используя алгоритм «work stealing» (кража работы).
  • Безопасные параллельные контейнеры — concurrent_vector, concurrent_queue и другие, которые можно использовать без ручной синхронизации.
  • Простота — для распараллеливания цикла достаточно заменить for на tbb::parallel_for.

TBB активно используется в высоконагруженных системах, научных вычислениях, обработке изображений, игровых движках и везде, где важна производительность. С 2020 года проект развивается под эгидой организации oneAPI и является открытым (Apache 2.0).

📦 Установка

Установка TBB зависит от вашей операционной системы и менеджера пакетов. Ниже приведены команды для основных платформ.

Linux (Ubuntu/Debian)

sudo apt update
sudo apt install libtbb-dev

macOS (Homebrew)

brew install tbb

Windows (vcpkg)

vcpkg install tbb

Сборка из исходников (CMake)

git clone https://github.com/oneapi-src/oneTBB.git
cd oneTBB
mkdir build && cd build
cmake .. -DCMAKE_INSTALL_PREFIX=/usr/local
make -j$(nproc)
sudo make install
Примечание: После установки убедитесь, что компилятор видит библиотеку. При компиляции добавляйте флаг -ltbb:
g++ -std=c++17 -O2 my_program.cpp -ltbb -o my_program

🚀 Быстрый старт

Минимальный рабочий пример: распараллеливание цикла, который вычисляет квадраты чисел.

#include <iostream>
#include <vector>
#include <tbb/parallel_for.h>

int main() {
    const int n = 100;
    std::vector<int> data(n, 1);

    // Параллельный for: каждый элемент умножается на 2
    tbb::parallel_for(0, n, [&](int i) {
        data[i] = data[i] * 2;
    });

    // Вывод первых 10 элементов
    for (int i = 0; i < 10; ++i) {
        std::cout << data[i] << " ";
    }
    std::cout << std::endl;
    return 0;
}

Этот код автоматически распределит итерации по всем доступным ядрам процессора. Никаких явных потоков, мьютексов или усложнённой логики — просто заменили for на tbb::parallel_for.

🧩 Основные методы, функции и классы

Рассмотрим 8 ключевых компонентов TBB, которые покрывают 90% задач параллельного программирования.

1. tbb::parallel_for

Сигнатура:

template<typename Index, typename Body>
void parallel_for(Index first, Index last, Body body, 
                  const tbb::auto_partitioner& partitioner = tbb::auto_partitioner{});

Что делает: Параллельно выполняет итерации цикла от first до last (не включая последний). Тело цикла (body) — это функтор или лямбда, принимающая индекс.

Пример:

#include <tbb/parallel_for.h>
#include <vector>

std::vector<double> vec(1000, 1.0);
tbb::parallel_for(0, (int)vec.size(), [&](int i) {
    vec[i] = std::sin(vec[i]) + std::cos(vec[i]);
});

2. tbb::parallel_reduce

Сигнатура:

template<typename Range, typename Value, typename Func, typename Reduction>
Value parallel_reduce(const Range& range, Value identity, Func func, Reduction reduction);

Что делает: Параллельно вычисляет редукцию (сумму, произведение, максимум и т.д.) элементов диапазона. identity — нейтральный элемент (0 для суммы, 1 для произведения).

Пример:

#include <tbb/parallel_reduce.h>
#include <vector>

std::vector<int> data = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
int sum = tbb::parallel_reduce(
    tbb::blocked_range<int>(0, data.size()),
    0,
    [&](const tbb::blocked_range<int>& r, int init) -> int {
        for (int i = r.begin(); i != r.end(); ++i)
            init += data[i];
        return init;
    },
    [](int a, int b) -> int { return a + b; }
);
// sum == 55

3. tbb::parallel_for_each

Сигнатура:

template<typename InputIterator, typename Body>
void parallel_for_each(InputIterator first, InputIterator last, Body body);

Что делает: Применяет функцию body к каждому элементу в диапазоне итераторов. Аналог std::for_each, но параллельный.

Пример:

#include <tbb/parallel_for_each.h>
#include <vector>
#include <string>

std::vector<std::string> words = {"hello", "world", "tbb", "parallel"};
tbb::parallel_for_each(words.begin(), words.end(), [](std::string& s) {
    std::transform(s.begin(), s.end(), s.begin(), ::toupper);
});
// words == {"HELLO", "WORLD", "TBB", "PARALLEL"}

4. tbb::parallel_sort

Сигнатура:

template<typename RandomAccessIterator>
void parallel_sort(RandomAccessIterator first, RandomAccessIterator last);

template<typename RandomAccessIterator, typename Compare>
void parallel_sort(RandomAccessIterator first, RandomAccessIterator last, Compare comp);

Что делает: Параллельная сортировка диапазона. Использует алгоритм быстрой сортировки с порогом переключения на последовательную сортировку для маленьких подмассивов.

Пример:

#include <tbb/parallel_sort.h>
#include <vector>
#include <random>

std::vector<int> v(100000);
std::generate(v.begin(), v.end(), std::rand);
tbb::parallel_sort(v.begin(), v.end());  // По возрастанию
// или с компаратором:
tbb::parallel_sort(v.begin(), v.end(), std::greater<int>());  // По убыванию

5. tbb::concurrent_vector

Сигнатура (основные методы):

template<typename T>
class concurrent_vector {
public:
    void push_back(const T& value);
    T& operator[](size_t index);
    size_t size() const;
    // ... другие методы
};

Что делает: Потокобезопасный динамический массив. Несколько потоков могут одновременно добавлять элементы (push_back) без блокировок. Доступ по индексу безопасен только если индекс уже существует.

Пример:

#include <tbb/concurrent_vector.h>
#include <tbb/parallel_for.h>

tbb::concurrent_vector<int> vec;
vec.reserve(1000);  // Зарезервировать место

tbb::parallel_for(0, 1000, [&](int i) {
    vec.push_back(i * i);  // Безопасно из нескольких потоков
});

6. tbb::concurrent_queue

Сигнатура (основные методы):

template<typename T>
class concurrent_queue {
public:
    void push(const T& value);
    bool try_pop(T& value);
    bool empty() const;
};

Что делает: Потокобезопасная очередь FIFO. Подходит для модели «производитель-потребитель». try_pop неблокирующий — возвращает false, если очередь пуста.

Пример:

#include <tbb/concurrent_queue.h>
#include <thread>

tbb::concurrent_queue<int> queue;

// Поток-производитель
std::thread producer([&]() {
    for (int i = 0; i < 100; ++i)
        queue.push(i);
});

// Поток-потребитель
std::thread consumer([&]() {
    int value;
    while (queue.try_pop(value)) {
        // Обработка value
    }
});

producer.join();
consumer.join();

7. tbb::task_group

Сигнатура (основные методы):

class task_group {
public:
    template<typename Func>
    void run(Func f);
    void wait();
};

Что делает: Позволяет запускать несколько задач асинхронно и дожидаться их завершения. Задачи выполняются в пуле потоков TBB.

Пример:

#include <tbb/task_group.h>
#include                    

Рекомендаций