Programação Assíncrona em C++: Guia Completo
Aplicações modernas exigem alta performance e responsividade. A programação assíncrona em C++ permite executar operações longas (entrada/saída, requisições de rede, cálculos complexos) sem bloquear a thread principal. Neste guia, abordaremos os principais mecanismos do C++ para trabalho assíncrono: desde os clássicos std::thread e std::async até as corrotinas modernas do C++20. Você aprenderá a escrever código assíncrono eficiente e seguro.
1. Fundamentos: std::thread e std::async
Vamos começar com as ferramentas básicas. std::thread cria uma nova thread de execução, mas requer gerenciamento manual e sincronização. Uma opção mais conveniente é std::async, que executa uma função de forma assíncrona e retorna um std::future para obter o resultado.
#include <iostream>#include <future>#include <chrono>
int long_running_task(int input) { std::this_thread::sleep_for(std::chrono::seconds(2)); return input * 10;}
int main() { std::cout << "Iniciando tarefa assíncrona..."; std::future<int> result = std::async(std::launch::async, long_running_task, 5); // Faz algo útil enquanto a tarefa é executada std::cout << "Thread principal continua trabalhando..."; // Obtém o resultado (bloqueia se a tarefa ainda não foi concluída) int value = result.get(); std::cout << "Resultado: " << value << std::endl; return 0;}Pontos-chave:
- std::launch::async — garante a execução em uma thread separada.
- std::launch::deferred — adia a execução até a chamada de
get(). - O método
get()bloqueia a thread até obter o resultado.
2. Trabalho Avançado: std::promise e std::future
Quando você precisa transferir um resultado de uma thread para outra, use o par std::promise e std::future. O promise define o valor, e o future o recebe. Isso é especialmente útil em pool de threads ou cadeias de tarefas.
#include <iostream>#include <future>#include <thread>
void worker(std::promise<int> prom) { try { int result = 42; // Cálculos complexos prom.set_value(result); } catch (...) { prom.set_exception(std::current_exception()); }}
int main() { std::promise<int> prom; std::future<int> fut = prom.get_future(); std::thread t(worker, std::move(prom)); // Obtém o resultado int value = fut.get(); std::cout << "Valor recebido: " << value << std::endl; t.join(); return 0;}Características importantes:
promisenão pode ser copiado, apenas movido.- Exceções são transmitidas através de
set_exception. futurepode ser usado apenas uma vez (obtenção única).
3. Corrotinas C++20: Abordagem Moderna
Corrotinas (coroutines) são uma ferramenta poderosa adicionada no C++20. Elas permitem pausar e retomar a execução de uma função sem bloquear a thread. Isso é ideal para operações assíncronas de entrada/saída e geradores.
#include <iostream>#include <coroutine>#include <future>
struct SimpleTask { struct promise_type { SimpleTask get_return_object() { return {}; } std::suspend_never initial_suspend() { return {}; } std::suspend_never final_suspend() noexcept { return {}; } void return_void() {} void unhandled_exception() { std::exit(1); } };};
SimpleTask async_operation() { std::cout << "Início da corrotina";