Colas de tareas en C++: guía práctica con ejemplos

Entrenador de Python en Línea para Principiantes

Aprende Python fácilmente sin sobrecargarte de teoría. Resuelve tareas prácticas con verificación automática, recibe pistas y escribe código directamente en el navegador, sin instalar nada.

Start Course

Introducción: ¿por qué se necesitan colas de tareas en C++?

\n\n

En la programación moderna, especialmente al trabajar con aplicaciones multiproceso, a menudo surge la necesidad de organizar la ejecución de tareas en el orden en que llegan. Las colas de tareas (task queues) son un patrón fundamental que permite distribuir eficientemente el trabajo entre hilos, procesar solicitudes de servidores web, gestionar procesos en segundo plano y evitar condiciones de carrera.

\n\n

En C++, la biblioteca estándar proporciona el potente contenedor std::queue, que es ideal para implementar colas de tareas. Sin embargo, en la práctica no solo se necesita almacenar elementos, sino transferirlos de forma segura entre hilos, manejar errores y gestionar el ciclo de vida de las tareas. En este artículo, analizaremos cómo crear colas de tareas en C++ desde cero, utilizando las capacidades modernas del lenguaje (C++11 y posteriores).

\n\n

Abordaremos:

\n
    \n
  • Uso básico de std::queue
  • \n
  • Cola de tareas segura para hilos
  • \n
  • Implementación de un grupo de hilos (thread pool)
  • \n
  • Colas prioritarias
  • \n
\n\n

1. Cola de tareas básica con std::queue

\n\n

Comencemos con un ejemplo simple. std::queue es un adaptador de contenedor que funciona bajo el principio FIFO (First In, First Out). Proporciona los métodos push(), pop(), front() y empty().

\n\n

Así es como se puede organizar una cola de tareas, donde cada tarea es una función (o un objeto invocable):

\n\n
#include <iostream>\n#include <queue>\n#include <functional>\n\nint main() {\n    // Cola de tareas, donde cada tarea es std::function<void()>\n    std::queue<std::function<void()>> taskQueue;\n\n    // Agregamos tareas\n    taskQueue.push([]() { std::cout << "Tarea 1 completada\\n"; });\n    taskQueue.push([]() { std::cout << "Tarea 2 completada\\n"; });\n    taskQueue.push([]() { std::cout << "Tarea 3 completada\\n"; });\n\n    // Procesamos la cola\n    while (!taskQueue.empty()) {\n        auto task = taskQueue.front();\n        task();  // Ejecutamos la tarea\n        taskQueue.pop();  // Eliminamos la tarea completada\n    }\n\n    return 0;\n}
\n\n

Este código funciona, pero solo en modo de un solo hilo. Si varios hilos agregan o extraen tareas simultáneamente, se producirá una condición de carrera. Para el multiproceso se necesita sincronización.

\n\n

2. Cola de tareas segura para hilos

\n\n

Para hacer que la cola sea segura para el acceso multiproceso, utilizamos un mutex (std::mutex) y una variable de condición (std::condition_variable). Este es el patrón clásico productor-consumidor.

\n\n

Implementación de una cola segura para hilos:

\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();  // Notificamos a un hilo en 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;  // Señal 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();  // Despertamos todos los hilos para finalizar\n    }\n};
\n\n

Puntos clave:

\n
    \n
  • std::lock_gu

Blogs

Book Recommendations