Очереди задач в C++: Полное руководство для начинающих

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

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

Начать курс

Введение в очереди задач в C++

Очередь задач (queue) — это одна из фундаментальных структур данных в программировании, которая работает по принципу FIFO (First In, First Out): первый добавленный элемент будет извлечён первым. Представьте себе обычную очередь в магазине — первый покупатель обслуживается первым. В C++ работа с очередями реализована через контейнер std::queue, который является частью Стандартной библиотеки шаблонов (STL).

В этой статье мы подробно разберём, как создавать, наполнять и обрабатывать очереди задач на C++. Вы узнаете, какие методы доступны, как избежать типичных ошибок и как очереди применяются в реальных проектах, от многопоточных систем до обработки запросов.

Основные операции с очередью задач

Создание и инициализация очереди

Чтобы использовать очередь в C++, необходимо подключить заголовочный файл <queue>. Базовая очередь объявляется так:

#include <iostream>
#include <queue>

int main() {
    std::queue<int> taskQueue; // Очередь целых чисел
    return 0;
}

Вы можете создать очередь для любого типа данных — строк, пользовательских структур, указателей. Например, очередь задач для обработки заказов:

#include <queue>
#include <string>

struct Order {
    int id;
    std::string description;
};

int main() {
    std::queue<Order> orderQueue;
    return 0;
}

Добавление и удаление элементов

Основные методы для работы с очередью:

  • push() — добавляет элемент в конец очереди
  • pop() — удаляет первый элемент из очереди
  • front() — возвращает ссылку на первый элемент (без удаления)
  • back() — возвращает ссылку на последний элемент
  • empty() — проверяет, пуста ли очередь
  • size() — возвращает количество элементов

Рассмотрим пример с пошаговой обработкой задач:

#include <iostream>
#include <queue>

int main() {
    std::queue<std::string> tasks;

    // Добавляем задачи
    tasks.push("Задача 1: Проверить почту");
    tasks.push("Задача 2: Написать отчёт");
    tasks.push("Задача 3: Провести совещание");

    std::cout << "Первая задача: " << tasks.front() << std::endl;
    std::cout << "Последняя задача: " << tasks.back() << std::endl;
    std::cout << "Всего задач: " << tasks.size() << std::endl;

    // Обрабатываем задачи по очереди
    while (!tasks.empty()) {
        std::cout << "Выполняю: " << tasks.front() << std::endl;
        tasks.pop(); // Удаляем выполненную задачу
    }

    std::cout << "Все задачи выполнены!" << std::endl;
    return 0;
}

Результат выполнения:

Первая задача: Задача 1: Проверить почту
Последняя задача: Задача 3: Провести совещание
Всего задач: 3
Выполняю: Задача 1: Проверить почту
Выполняю: Задача 2: Написать отчёт
Выполняю: Задача 3: Провести совещание
Все задачи выполнены!

Приоритетные очереди: когда порядок важен

Иногда задачи имеют разный приоритет. Например, критическая ошибка должна быть обработана раньше планового обновления. В таких случаях используется std::priority_queue, которая автоматически сортирует элементы по приоритету.

#include <iostream>
#include <queue>
#include <vector>

int main() {
    // По умолчанию — максимальный приоритет у наибольшего элемента
    std::priority_queue<int> highPriorityTasks;

    highPriorityTasks.push(5); // Обычная задача
    highPriorityTasks.push(10); // Срочная задача
    highPriorityTasks.push(1); // Низкий приоритет

    while (!highPriorityTasks.empty()) {
        std::cout << "Обрабатываю задачу с приоритетом: " 
                  << highPriorityTasks.top() << std::endl;
        highPriorityTasks.pop();
    }
    return 0;
}

Вывод:

Обрабатываю задачу с приоритетом: 10
Обрабатываю задачу с приоритетом: 5
Обрабатываю задачу с приоритетом: 1

Чтобы изменить порядок на обратный (низкий приоритет — первым), используйте:

std::priority_queue<int, std::vector<int>, std::greater<int>> lowFirstQueue;

Реальные сценарии использования очередей

Обработка запросов в веб-сервере

Представьте, что ваш сервер получает множество HTTP-запросов. Очередь позволяет обрабатывать их по порядку, не теряя ни одного:

#include <iostream>
#include <queue>
#include <string>

struct Request {
    int id;
    std::string url;
};

class RequestHandler {
private:
    std::queue<Request> pendingRequests;
public:
    void addRequest(int id, const std::string& url) {
        pendingRequests.push({id, url});
        std::cout << "Запрос " << id << " добавлен в очередь\n";
    }

    void processAll() {
        while (!pendingRequests.empty()) {
            Request req = pendingRequests.front();
            std::cout << "Обрабатываю запрос " << req.id 
                      << " к " << req.url << std::endl;
            // Здесь может быть реальная обработка
            pendingRequests.pop();
        }
    }
};

int main() {
    RequestHandler handler;
    handler.addRequest(1, "/api/users");
    handler.addRequest(2, "/api/data");
    handler.addRequest(3, "/api/login");
    handler.processAll();
    return 0;
}

Многопоточная очередь задач

В многопоточных приложениях очереди часто используются для передачи задач между потоками. Однако стандартная std::queue не является потокобезопасной. Для безопасной работы используйте мьютексы или готовые решения, например, tbb::concurrent_queue из библиотеки Intel TBB.

Блоги

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