Очереди задач для C++: обзор библиотек и реализация

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

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

Начать курс

Очереди задач для C++: полное руководство по выбору и реализации

В современном программировании на C++ эффективное использование многопоточности — залог производительности приложений. Одним из ключевых паттернов является очередь задач (task queue), которая позволяет распределять работу между потоками без ручного управления их жизненным циклом. В этой статье мы разберём лучшие библиотеки для C++, предоставляющие готовые решения, а также покажем, как реализовать очередь задач своими руками.

Что такое очередь задач и зачем она нужна

Очередь задач — это механизм, при котором вы помещаете в очередь «задания» (функции, лямбды или объекты), а пул потоков (thread pool) автоматически их выполняет. Это избавляет от необходимости создавать и завершать потоки для каждой задачи, снижает накладные расходы и упрощает синхронизацию.

Основные преимущества:

  • Автоматическое распределение нагрузки между ядрами CPU
  • Повторное использование потоков (экономия ресурсов)
  • Простота добавления новых задач без блокировок
  • Возможность приоритезации и отмены задач

Популярные библиотеки для очередей задач в C++

1. Intel Threading Building Blocks (TBB)

Одна из самых мощных библиотек, разработанная Intel. Предоставляет tbb::parallel_for, tbb::task_group и гибкий планировщик задач. Подходит для высокопроизводительных вычислений.

#include <tbb/task_group.h>
#include <iostream>

int main() {
    tbb::task_group tg;
    tg.run([] { std::cout << "Задача 1\n"; });
    tg.run([] { std::cout << "Задача 2\n"; });
    tg.wait(); // дождаться завершения
    return 0;
}

2. Boost.Task (устарел, но концепции живы в Boost.Fiber)

Раньше в Boost была библиотека Boost.Task, сейчас её функционал частично перешёл в Boost.Fiber. Позволяет создавать очереди с приоритетами и асинхронными результатами.

// Пример с Boost.Fiber (современная альтернатива)
#include <boost/fiber/all.hpp>
#include <iostream>

int main() {
    boost::fibers::fiber f1([]{
        std::cout << "Файбер 1\n";
    });
    f1.join();
    return 0;
}

3. PPL (Parallel Patterns Library) — для Windows

Библиотека от Microsoft, встроенная в Visual Studio. Использует concurrency::task и concurrency::parallel_for. Отлично интегрируется с Windows Runtime.

#include <ppltasks.h>
#include <iostream>

int main() {
    concurrency::create_task([]{
        std::cout << "Задача PPL\n";
    }).wait();
    return 0;
}

4. QtConcurrent — для проектов на Qt

Если вы используете Qt, QtConcurrent::run и QThreadPool — простой способ организовать очередь задач.

#include <QtConcurrent/QtConcurrentRun>
#include <iostream>

int main() {
    QtConcurrent::run([]{
        std::cout << "Задача Qt\n";
    });
    QThread::msleep(100);
    return 0;
}

Реализация простой очереди задач на std::thread

Если вы не хотите подключать внешние библиотеки, можно написать свою очередь. Ниже — минимальный рабочий пример на C++17.

#include <iostream>
#include <queue>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <functional>

class TaskQueue {
public:
    explicit TaskQueue(size_t threads) {
        for (size_t i = 0; i < threads; ++i) {
            workers.emplace_back([this] {
                while (true) {
                    std::function<void()> task;
                    {
                        std::unique_lock<std::mutex> lock(mutex);
                        condition.wait(lock, [this] {
                            return stop || !tasks.empty();
                        });
                        if (stop && tasks.empty()) return;
                        task = std::move(tasks.front());
                        tasks.pop();
                    }
                    task();
                }
            });
        }
    }

    template<class F>
    void enqueue(F&& f) {
        {
            std::lock_guard<std::mutex> lock(mutex);
            tasks.emplace(std::forward<F>(f));
        }
        condition.notify_one();
    }

    ~TaskQueue() {
        {
            std::lock_guard<std::mutex> lock(mutex);
            stop = true;
        }
        condition.notify_all();
        for (auto& worker : workers) {
            worker.join();
        }
    }

private:
    std::vector<                    

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