Какие способы запуска потока существуют в C++
Что проверяют
Различаете ли вы запуск потока и запуск задачи и понимаете ли, кто владеет потоком. Вопрос простой, но интервьюер ждёт продолжения про join, detach и передачу аргументов. Следом обычно спрашивают, что случится с программой, если поток не присоединить.
Как отвечать
Перечислите способы и сразу давайте ограничения:
std::thread(C++11): принимает вызываемый объект и аргументы, копирует их, ссылку нужно оборачивать вstd::ref. Деструктор ещё присоединяемого потока вызываетstd::terminate, поэтомуjoinилиdetachобязательны;std::jthread(C++20): то же самое, но присоединяется в деструкторе и поддерживает кооперативную отмену черезstd::stop_tokenиrequest_stop(). По умолчанию берите его;std::async: возвращаетstd::future. С политикойstd::launch::asyncпоток стартует сразу, сstd::launch::deferredфункция выполнится лениво при вызовеget(). Без явной политики выбор за реализацией, поэтому её указывают. Отдельная особенность: деструктор future, полученного изasync, блокируется до конца задачи;std::packaged_taskиstd::promise: разделяют «что посчитать» и «где выполнить», это кирпичи для собственного пула;- пул потоков: своя очередь задач или библиотека. В стандарте исполнителей долго не было, модель
std::executionпоявилась только в C++26; - параллельные алгоритмы (C++17):
std::for_eachи другие с политикойstd::execution::par, потоками управляет реализация; - платформенное:
pthread_create,CreateThread, OpenMP. Нужны, когда важны приоритет, привязка к ядру или размер стека.
Добавьте, что std::thread::hardware_concurrency() это лишь подсказка о числе аппаратных потоков и может вернуть ноль, а тысячу коротких задач отдают пулу: создание потока стоит дорого.
Где спотыкаются
Захватывают в лямбду локальные переменные по ссылке: функция вышла, а поток читает мёртвый стек.
Пишут std::async(f) без политики, получают отложенное выполнение и не понимают, почему работа не идёт параллельно.
Забывают про исключения: вылетевшее из std::thread исключение завершает всю программу, а из std::async оно спокойно ждёт и прилетает при future::get().