Introdução à programação assíncrona em C++
\n\nNo mundo moderno do desenvolvimento de software, o desempenho e a capacidade de resposta dos aplicativos desempenham um papel fundamental. A programação assíncrona em C++ permite utilizar eficientemente os recursos do sistema, executando várias tarefas simultaneamente sem bloquear o thread principal. Isso é especialmente importante ao trabalhar com requisições de rede, operações de entrada/saída e cálculos longos.
\n\nAo contrário da abordagem síncrona tradicional, onde cada operação é executada sequencialmente, o código assíncrono pode iniciar tarefas em segundo plano e obter resultados à medida que ficam prontos. Neste guia, abordaremos as principais ferramentas de programação assíncrona em C++, começando com conceitos simples e terminando com os recursos modernos do padrão C++20.
\n\nFundamentos da assincronia: std::async e std::future
\n\nA maneira mais simples de começar a trabalhar com programação assíncrona em C++ é usar std::async. Esta função inicia uma tarefa de forma assíncrona e retorna um objeto std::future, que contém o resultado da execução.
Exemplo básico com std::async
\n\n#include <iostream>\n#include <future>\n#include <chrono>\n\nint operacao_demorada() {\n std::this_thread::sleep_for(std::chrono::seconds(2));\n return 42;\n}\n\nint main() {\n std::cout << "Iniciando tarefa assíncrona..." << std::endl;\n \n // Iniciar tarefa assíncrona\n std::future<int> resultado = std::async(std::launch::async, operacao_demorada);\n \n std::cout << "Thread principal continua trabalhando..." << std::endl;\n \n // Obter o resultado (bloqueia o thread até ficar pronto)\n int valor = resultado.get();\n std::cout << "Resultado: " << valor << std::endl;\n \n return 0;\n}\n\nA política de inicialização std::launch::async garante que a função será executada em um thread separado. A alternativa é std::launch::deferred, que adia a execução até o momento da chamada get().
Trabalhando com várias tarefas
\n\nA programação assíncrona é especialmente eficaz na execução paralela de várias tarefas independentes:
\n\n#include <iostream>\n#include <future>\n#include <vector>\n\nint calcular_quadrado(int x) {\n return x * x;\n}\n\nint main() {\n std::vector<std::future<int>> tarefas;\n \n // Iniciar várias tarefas assíncronas\n for (int i = 1; i <= 5; ++i) {\n tarefas.push_back(std::async(std::launch::async, calcular_quadrado, i));\n }\n \n // Coletar os resultados\n for (auto& tarefa : tarefas) {\n std::cout << "Resultado: " << tarefa.get() << std::endl;\n }\n \n return 0;\n}\n\nFerramentas avançadas: std::promise e std::packaged_task
\n\nPara um gerenciamento mais flexível de operações assíncronas em C++, existem std::promise e std::packaged_task. Essas ferramentas permitem transmitir valores entre threads e encapsular objetos chamáveis.
Usando std::promise
\n\nstd::promise permite definir um valor que posteriormente será obtido através do objeto std::future correspondente:
#include <iostream>\n#include <future>\n#include <thread>\n\nvoid thread_produtor(std::promise<std::string> promessa) {\n try {\n std::string dados = "Dados importantes do thread";\n // Define o valor\n promessa.set_value(dados);\n } catch(...) {\n // Tratamento de exceções\n promessa.set_exception(std::current_exception());\n }\n}\n\nint main() {\n std::promise<std::string> promessa;\n std::future<std::string> futuro = promessa.get_future();\n \n std::thread thread(pro