async, future и время: chrono
Функция, запущенная в 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
}std::async передаёт аргумент 100 в sum_to. В угловых скобках std::future<int> стоит тип результата. Вызов result.get() ждёт, пока функция закончит работу, и возвращает её результат. Вызвать get() у одного std::future можно только один раз, а wait() только ждёт, не забирая результат.
Политика запуска
Первый аргумент std::async — политика запуска (launch policy). С std::launch::async функция выполняется в новом потоке. С std::launch::deferred она сразу не запускается: её выполнит первый вызов get() или wait(), в том потоке, который его сделал. Если не вызвать ни то, ни другое, функция не выполнится вовсе.
Политику можно не указывать: std::async(sum_to, 100). Тогда между async и deferred выбирает реализация стандартной библиотеки. Если задача должна идти параллельно, передайте std::launch::async явно.
Длительности: chrono
Потоку часто нужно подождать: std::this_thread::sleep_for приостанавливает его на заданную длительность (duration). Длительности задают типы std::chrono::seconds, std::chrono::minutes и std::chrono::milliseconds из заголовка <chrono>. Метод .count() возвращает число единиц. Литералы 2min, 30s и 500ms доступны после строки using namespace std::chrono_literals;.
#include <chrono>
#include <iostream>
using namespace std::chrono_literals;
int main() {
std::chrono::seconds total = 2min + 30s;
std::chrono::milliseconds ms = total;
std::cout << total.count() << ' ' << ms.count() << '\n'; // 150 150000
}Сумма 2min + 30s получает тип более мелкой из двух единиц, то есть секунды. В более мелкие единицы длительность переводится сама: точность при этом не теряется. Обратный перевод может потерять дробную часть, поэтому его пишут явно, через std::chrono::duration_cast. Он округляет к нулю: std::chrono::duration_cast<std::chrono::seconds>(1500ms) равно 1s.
Частая ошибка
Миллисекунды присваивают секундам:
std::chrono::milliseconds ms{1500};
std::chrono::seconds s = ms; // ✗error: no viable conversion from 'duration<[...], ratio<[...], 1000>>' to 'duration<[...], ratio<[...], 1>>'Это ошибка компилятора (compiler). Он проверяет типы, а не значение: перевод миллисекунд в секунды может потерять дробную часть, даже если бы в ms было ровно 2000. Если потеря допустима, переведите через duration_cast.