Introducción a la programación asíncrona en C++
Las aplicaciones modernas requieren cada vez más alto rendimiento y capacidad de respuesta. La programación asíncrona en C++ es una herramienta poderosa que permite ejecutar múltiples tareas simultáneamente sin bloquear el hilo principal de ejecución. En esta guía, analizaremos los fundamentos de la asincronía en C++: desde enfoques clásicos hasta las corrutinas (coroutines) modernas, añadidas en el estándar C++20.
Si eres nuevo en C++, pero ya conoces la sintaxis básica, este artículo te ayudará a entender cómo hacer que tu programa realice varias cosas al mismo tiempo. Veremos ejemplos prácticos que puedes aplicar inmediatamente en tus proyectos.
Conceptos principales y por qué es necesario
En la programación síncrona tradicional, el código se ejecuta estrictamente de forma secuencial: una operación termina, luego comienza la siguiente. Esto es simple, pero ineficiente si el programa espera entrada/salida (lectura de archivo, solicitud de red) o realiza cálculos pesados.
La programación asíncrona resuelve este problema, permitiendo:
- No bloquear el hilo principal — la interfaz de la aplicación permanece receptiva.
- Acelerar la ejecución — procesamiento paralelo de datos en procesadores multinúcleo.
- Usar recursos eficientemente — mientras una tarea espera datos, otra puede ejecutarse.
En C++ existen varias formas de implementar la asincronía: desde hilos de bajo nivel (std::thread) hasta abstracciones de alto nivel (std::async, std::future y corrutinas).
1. Asincronía con std::async y std::future
La forma más simple de ejecutar una tarea asíncrona en C++ es usar la función std::async del archivo de cabecera <future>. Esta devuelve un objeto std::future que almacena el resultado de la ejecución.
Ejemplo básico
#include <iostream>#include <future>#include <thread>#include <chrono>
// Función que se ejecutará de forma asíncronaint slow_calculation(int x) { std::this_thread::sleep_for(std::chrono::seconds(2)); // Simulación de trabajo largo return x * x;}
int main() { std::cout << "Iniciando tarea asíncrona..." << std::endl; // Ejecutamos slow_calculation en un hilo separado std::future<int> result = std::async(std::launch::async, slow_calculation, 5); std::cout << "El hilo principal continúa trabajando..." << std::endl; // Obtenemos el resultado (bloquea el hilo si la tarea aún no ha terminado) int value = result.get(); std::cout << "Resultado: " << value << std::endl; // Salida: 25 return 0;}En este ejemplo, std::async ejecuta la función en un hilo separado. Mientras se ejecuta, el hilo principal muestra un mensaje. El método get() espera a que la tarea termine y devuelve el resultado.
Políticas de lanzamiento
std::async tiene dos modos:
std::launch::async— la tarea se ejecuta garantizadamente en un nuevo hilo.std::launch::deferred— la tarea se ejecuta de forma diferida, solo al llamar aget()owait()en el mismo hilo.
2. Promises y Futures: gestión manual
Si necesitas un control más flexible sobre las tareas asíncronas, usa el par std::promise y std::future. promise permite establecer un valor o excepción en un hilo, y future permite obtenerlo en otro.
Ejemplo con promise
#include <iostream>#include <future>#include <thread>
void worker(std::promise<int> prom, int a, int b) { try { int result = a / b; // Puede