async и future
Вы заказываете на кухне суп и получаете талон с номером. Пока суп варится, вы заняты своим. Когда суп нужен, вы подходите к окну выдачи с талоном: если суп готов, его отдают сразу, если нет — ждёте у окна. Талон обменивают на суп один раз.
Функция, запущенная в std::thread, не может вернуть результат: возвращённое значение поток отбрасывает. Чтобы забрать результат, приходится заводить общую переменную и вызывать join(). Функция std::async из заголовка <future> упрощает это. Она запускает функцию и возвращает std::future — объект, из которого результат забирают позже, тот самый талон:
#include <future>
#include <iostream>
int sum_to(int n) {
int sum = 0;
for (int i = 1; i <= n; ++i) {
sum += i;
}
return sum;
}
int main() {
std::future<int> result = std::async(std::launch::async, sum_to, 100);
std::cout << result.get() << '\n'; // 5050
}Талон и результат
Давайте разберём main по частям:
std::async(std::launch::async, sum_to, 100)запускаетsum_toи передаёт ей аргумент100.std::future<int>— тип талона; в угловых скобках стоит тип результата, здесьint.result.get()ждёт, пока функция закончит работу, и возвращает её результат:5050.
У std::future два способа дождаться функции:
get()ждёт и забирает результат; вызвать его у одногоstd::futureможно только один раз, как один раз обменивают талон;wait()только ждёт, не забирая результат.
Здесь аналогия с талоном заканчивается: у окна выдачи использованный талон не примут, а повторный get() — неопределённое поведение. Стандарт не обещает ни отказа, ни результата.
Политика запуска
Первый аргумент std::async — политика запуска. Она решает, когда и где выполнится функция.
std::launch::async
Функция выполняется в новом потоке и начинает работу сразу. Это кухня, которая берётся за суп, как только приняла заказ.
std::launch::deferred
Функция сразу не запускается: её выполнит первый вызов get() или wait(), в том потоке, который его сделал. Это кухня, которая начинает варить, только когда вы подошли к окну с талоном. Если не вызвать ни get(), ни wait(), функция не выполнится вовсе.
Без политики
Политику можно не указывать: std::async(sum_to, 100). Тогда между async и deferred выбирает реализация стандартной библиотеки. Если задача должна идти параллельно, передайте std::launch::async явно. На собеседовании любят спрашивать, выполнится ли функция без явной политики.
Главное
std::asyncзапускает функцию и возвращаетstd::future, из которого результат забирают позже.get()ждёт и возвращает результат, и вызвать его можно только один раз;wait()только ждёт.- С
std::launch::asyncфункция выполняется в новом потоке, сstd::launch::deferred— при первомget()илиwait(). - Без явной политики выбор делает библиотека; для параллельной работы передайте
std::launch::async.
Подпишись, чтобы пройти курс
Курс бесплатный. Войди через Telegram и подпишись на канал — откроются все уроки.