Introducción a la programación asíncrona en C++
\n\nEn el mundo moderno del desarrollo de software, el rendimiento y la capacidad de respuesta de las aplicaciones juegan un papel clave. La programación asíncrona en C++ permite utilizar eficientemente los recursos del sistema, ejecutando múltiples tareas simultáneamente sin bloquear el hilo principal. Esto es especialmente importante al trabajar con solicitudes de red, operaciones de entrada/salida y cálculos prolongados.
\n\nA diferencia del enfoque síncrono tradicional, donde cada operación se ejecuta secuencialmente, el código asíncrono puede ejecutar tareas en segundo plano y obtener los resultados a medida que estén listos. En esta guía, exploraremos las herramientas principales de la programación asíncrona en C++, comenzando con conceptos simples y terminando con las capacidades modernas del estándar C++20.
\n\nFundamentos de la asincronía: std::async y std::future
\n\nLa forma más sencilla de comenzar con la programación asíncrona en C++ es usar std::async. Esta función ejecuta una tarea de forma asíncrona y devuelve un objeto std::future que contiene el resultado de la ejecución.
Ejemplo básico con std::async
\n\n#include <iostream>\n#include <future>\n#include <chrono>\n\nint operacion_larga() {\n std::this_thread::sleep_for(std::chrono::seconds(2));\n return 42;\n}\n\nint main() {\n std::cout << "Iniciando tarea asíncrona..." << std::endl;\n \n // Inicio de tarea asíncrona\n std::future<int> resultado = std::async(std::launch::async, operacion_larga);\n \n std::cout << "El hilo principal continúa trabajando..." << std::endl;\n \n // Obtención del resultado (bloquea el hilo hasta que esté listo)\n int valor = resultado.get();\n std::cout << "Resultado: " << valor << std::endl;\n \n return 0;\n}\n\nLa política de lanzamiento std::launch::async garantiza que la función se ejecutará en un hilo separado. La alternativa es std::launch::deferred, que retrasa la ejecución hasta que se llame a get().
Trabajo con múltiples tareas
\n\nLa programación asíncrona es especialmente efectiva al ejecutar varias tareas independientes en paralelo:
\n\n#include <iostream>\n#include <future>\n#include <vector>\n\nint calcular_cuadrado(int x) {\n return x * x;\n}\n\nint main() {\n std::vector<std::future<int>> tareas;\n \n // Iniciamos varias tareas asíncronas\n for (int i = 1; i <= 5; ++i) {\n tareas.push_back(std::async(std::launch::async, calcular_cuadrado, i));\n }\n \n // Recolectamos los resultados\n for (auto& tarea : tareas) {\n std::cout << "Resultado: " << tarea.get() << std::endl;\n }\n \n return 0;\n}\n\nHerramientas avanzadas: std::promise y std::packaged_task
\n\nPara un control más flexible de las operaciones asíncronas en C++, se proporcionan std::promise y std::packaged_task. Estas herramientas permiten transferir valores entre hilos y envolver objetos invocables.
Uso de std::promise
\n\nstd::promise permite establecer un valor que posteriormente se obtendrá a través del objeto std::future correspondiente:
#include <iostream>\n#include <future>\n#include <thread>\n\nvoid hilo_productor(std::promise<std::string> promesa) {\n try {\n std::string datos = "Datos importantes desde el hilo";\n // Establecemos el valor\n promesa.set_value(datos);\n } catch(...) {\n // Manejo de excepciones\n promesa.set_exception(std::current_exception());\n }\n}\n\nint main() {\n std::promise<std::string> promesa;\n std::future<std::string> futuro = promesa.get_future();\n \n std::thread hilo(pro