Filas de Tarefas em C++: Guia Prático com Exemplos

Treinador Online de Python para Iniciantes

Aprenda Python facilmente sem sobrecarga teórica. Resolva tarefas práticas com verificação automática e escreva código diretamente no navegador.

Start Course

Introdução: por que precisamos de filas de tarefas em C++?

\n\n

Na programação moderna, especialmente ao trabalhar com aplicações multithread, surge frequentemente a necessidade de organizar a execução de tarefas na ordem em que chegam. As filas de tarefas (task queues) são um padrão fundamental que permite distribuir eficientemente o trabalho entre threads, processar requisições de servidores web, gerenciar processos em segundo plano e evitar condições de corrida.

\n\n

Em C++, a biblioteca padrão fornece o poderoso contêiner std::queue, que é ideal para implementar filas de tarefas. No entanto, na prática, não basta apenas armazenar elementos; é necessário transferi-los com segurança entre threads, tratar erros e gerenciar o ciclo de vida das tarefas. Neste artigo, vamos analisar como criar filas de tarefas em C++ do zero, usando os recursos modernos da linguagem (C++11 e posteriores).

\n\n

Abordaremos:

\n
    \n
  • Funcionamento básico com std::queue
  • \n
  • Fila de tarefas thread-safe
  • \n
  • Implementação de um pool de threads (thread pool)
  • \n
  • Filas prioritárias
  • \n
\n\n

1. Fila de tarefas básica com std::queue

\n\n

Vamos começar com um exemplo simples. std::queue é um contêiner adaptador que opera no princípio FIFO (First In, First Out). Ele fornece os métodos push(), pop(), front() e empty().

\n\n

Aqui está como organizar uma fila de tarefas, onde cada tarefa é uma função (ou um objeto chamável):

\n\n
#include <iostream>\n#include <queue>\n#include <functional>\n\nint main() {\n    // Fila de tarefas, onde cada tarefa é um std::function<void()>\n    std::queue<std::function<void()>> taskQueue;\n\n    // Adicionando tarefas\n    taskQueue.push([]() { std::cout << "Tarefa 1 executada\\n"; });\n    taskQueue.push([]() { std::cout << "Tarefa 2 executada\\n"; });\n    taskQueue.push([]() { std::cout << "Tarefa 3 executada\\n"; });\n\n    // Processando a fila\n    while (!taskQueue.empty()) {\n        auto task = taskQueue.front();\n        task();  // Executa a tarefa\n        taskQueue.pop();  // Remove a tarefa executada\n    }\n\n    return 0;\n}
\n\n

Este código funciona, mas apenas em modo single-thread. Se várias threads adicionarem ou removerem tarefas simultaneamente, ocorrerá uma condição de corrida. Para multithreading, é necessária sincronização.

\n\n

2. Fila de tarefas thread-safe

\n\n

Para tornar a fila segura para acesso multithread, usamos um mutex (std::mutex) e uma variável de condição (std::condition_variable). Este é o padrão clássico produtor-consumidor (producer-consumer).

\n\n

Implementação de uma fila thread-safe:

\n\n
#include <queue>\n#include <mutex>\n#include <condition_variable>\n#include <functional>\n#include <thread>\n\nclass ThreadSafeQueue {\nprivate:\n    std::queue<std::function<void()>> queue_;\n    std::mutex mutex_;\n    std::condition_variable cond_;\n    bool stop_ = false;\n\npublic:\n    void push(std::function<void()> task) {\n        std::lock_guard<std::mutex> lock(mutex_);\n        queue_.push(task);\n        cond_.notify_one();  // Notifica uma thread em espera\n    }\n\n    std::function<void()> pop() {\n        std::unique_lock<std::mutex> lock(mutex_);\n        cond_.wait(lock, [this]() { return !queue_.empty() || stop_; });\n        if (stop_ && queue_.empty()) {\n            return nullptr;  // Sinal de parada\n        }\n        auto task = queue_.front();\n        queue_.pop();\n        return task;\n    }\n\n    void stop() {\n        std::lock_guard<std::mutex> lock(mutex_);\n        stop_ = true;\n        cond_.notify_all();  // Acorda todas as threads para finalizar\n    }\n};
\n\n

Pontos-chave:

\n
    \n
  • std::lock_gu

Blogs

Book Recommendations