Filas de Tarefas para C++: da Teoria à Prática
A fila de tarefas (task queue) é um dos padrões-chave da programação multithread em C++. Ela permite distribuir o trabalho de forma eficiente entre as threads, evitando condições de corrida e consumo excessivo de recursos. Neste artigo, vamos abordar como criar e usar filas de tarefas em C++, com foco em desempenho e segurança.
Por que uma fila de tarefas?
Em aplicações modernas, surge frequentemente a necessidade de executar várias tarefas pequenas em paralelo. Criar threads diretamente para cada tarefa gera custos indiretos: a criação de uma thread consome tempo e memória. A fila de tarefas resolve esse problema através de um pool de threads (thread pool):
- Reutilização de threads — as threads não são destruídas após a execução da tarefa, mas retornam ao pool.
- Balanceamento de carga — as tarefas são distribuídas uniformemente.
- Gerenciamento de recursos — limitação do número de threads simultâneas.
Implementação básica de uma fila de tarefas em C++
Vamos considerar uma fila de tarefas simples, mas thread-safe, usando std::queue e mutexes. Para isso, utilizamos a biblioteca padrão C++11 e superior.
#include <queue>#include <mutex>#include <condition_variable>#include <functional>#include <thread>#include <vector>
class TaskQueue {public: using Task = std::function<void()>;
explicit TaskQueue(size_t numThreads) : stop(false) { for (size_t i = 0; i < numThreads; ++i) { workers.emplace_back([this] { workerLoop(); }); } }
~TaskQueue() { { std::unique_lock<std::mutex> lock(mutex); stop = true; } condition.notify_all(); for (auto& worker : workers) { if (worker.joinable()) { worker.join(); } } }
void enqueue(Task task) { { std::unique_lock<std::mutex> lock(mutex); tasks.push(std::move(task)); } condition.notify_one(); }
private: void workerLoop() { while (true) { Task 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(); // Execução da tarefa } }
std::queue<Task> tasks; std::mutex mutex; std::condition_variable condition; bool stop; std::vector<std::thread> workers;};Exemplo de uso
Agora, vamos mostrar como usar nossa classe TaskQueue para executar cálculos simples em paralelo:
#include <iostream>
int main() { TaskQueue tq(4); // Pool de 4 threads
for (int i = 0; i < 10; ++i) { tq.enqueue([i] { std::cout << "Tarefa " << i << " executada pela thread " << std::this_thread::get_id() << std::endl; }); }
// O destrutor de tq aguardará a conclusão de todas as tarefas return 0;}Recursos avançados: fila com prioridades
Às vezes, é necessário processar tarefas na ordem de sua importância. Para isso, podemos usar std::priority_queue em vez de uma fila comum. Vamos adicionar suporte a prioridades:
#include <queue>#include <functional>
class PriorityTaskQueue {public: using Task = std::function<void()>;
struct PrioritizedTask { int priority; Task t Também na biblioteca
Trabalhando com S3 e armazenamentos em nuvem em TypeScript: guia completo
Geolocalização e Mapas em C# (.NET): bibliotecas, exemplos e recomendações
Contêiner de Injeção de Dependência para Kotlin: Koin vs Kodein vs Dagger
Logging em Kotlin: melhores bibliotecas e ferramentas para desenvolvimento
Autorização e autenticação em PHP: guia completo com exemplos