Что такое асинхронная операция в контексте C++?

«Что такое асинхронная операция в контексте C++?» — вопрос из категории Многопоточность, который задают на 25% собеседований C/C++ Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

В C++ асинхронная операция — это такая операция, инициация которой не блокирует поток выполнения, запустивший её. Вместо ожидания немедленного результата, поток получает объект-обещание (std::future), через который можно будет позже запросить результат (дождавшись его или проверив готовность). Сама операция выполняется "где-то ещё" — в отдельном потоке, пуле потоков или с использованием механизмов асинхронного ввода-вывода ОС.

Практический пример с std::async:

#include <iostream>
#include <future>
#include <thread>
#include <chrono>

// Долгая операция (например, запрос к API или сложный расчет)
std::string fetchDataFromNetwork(const std::string& url) {
    std::this_thread::sleep_for(std::chrono::seconds(3)); // Имитация сетевой задержки
    return "Data from " + url;
}

int main() {
    std::cout << "[Main] Starting async network request..." << std::endl;

    // Запускаем асинхронную задачу. std::launch::async гарантирует запуск в новом потоке.
    std::future<std::string> futureResult = std::async(std::launch::async, fetchDataFromNetwork, "https://api.example.com");

    std::cout << "[Main] Request sent. Doing other useful work..." << std::endl;
    // Основной поток НЕ заблокирован и может выполнять другую работу.
    std::this_thread::sleep_for(std::chrono::seconds(1));
    std::cout << "[Main] Still working..." << std::endl;

    // Когда результат понадобился, получаем его.
    // Вызов futureResult.get() БЛОКИРУЕТ текущий поток до завершения асинхронной операции.
    std::string data = futureResult.get();
    std::cout << "[Main] Received: " << data << std::endl;

    return 0;
}

Ключевые компоненты и альтернативы в C++:

  • std::async / std::future / std::promise: Высокоуровневый API из <future>.
  • std::thread + ручная синхронизация: Более низкоуровневый контроль.
  • Асинхронный I/O (Boost.Asio, io_uring): Для неблокирующих сетевых операций и работы с файлами.
  • Корутины (C++20): Позволяют писать асинхронный код в синхронном, последовательном стиле с использованием ключевых слов co_await, co_return.

Зачем это нужно: Для создания отзывчивых приложений, где нельзя блокировать основной поток (например, UI-поток в графическом приложении), и для эффективного распараллеливания задач, связанных с ожиданием (сеть, диск).