Daily bit(e) C++. std::promise, std::future
Daily bit(e) C++ 26. Инструменты высокоуровневой синхронизации, реализующие семантику одноразовых поставщика/потребителя: std::promise и std::future.

std::promise и std::future – это инструменты высокоуровневой синхронизации, реализующие семантику одноразовых поставщика/потребителя.
Поставщик может заполнить состояние std::promise либо значением, либо исключением. Потребитель, хранящий std::future, связанный с этим std::promise, может вызвать get(), чтобы блокировать выполнение до тех пор, пока не станет доступно общее состояние, после чего get() либо повторно выбросит исключение, либо вернет значение.
Обратите внимание, что доступ к общему состоянию возможен только один раз.
std::future также поддерживает тайм-аут/крайний срок через методы wait_for() и wait_until().
#include <future>
#include <thread>
#include <stdexcept>
using namespace std::literals;
std::promise<std::string> promise;
// Future предоставляется из promise.
std::future<std::string> future = promise.get_future();
auto t1 = std::jthread([promise = std::move(promise)] mutable {
std::this_thread::sleep_for(100ms);
// Устанавливаем значение, это разблокирует потребителя (future).
promise.set_value("Hello World!"s);
// Если предпочтительно заблокировать до завершения данного потока:
// promise.set_value_at_thread_exit("Hello World!"s);
});
// Заблокирует, пока значение не станет доступно,
// затем вернет сохраненное значение:
std::string value = future.get();
// Promise/Future также могут распространять исключения:
std::promise<int> other;
std::future<int> will_fail = other.get_future();
auto t2 = std::jthread([promise = std::move(other)] mutable {
try {
throw std::runtime_error("Some error happened.");
promise.set_value(10); // недостижимо
} catch (...) {
promise.set_exception(std::current_exception());
// так же, как и выше, можем сделать подобное:
// promise.set_exception_at_thread_exit(
// std::current_exception());
}
});
try {
// Блокирует, пока значение не станет доступно, в этом случае,
// вместо него будет передано исключение.
int v = will_fail.get();
// недостижимо
} catch (const std::exception& e) {
// e.what() == Произошла какая-то ошибка.
}
std::promise<void> slow;
std::future<void> will_timeout = slow.get_future();
auto t3 = std::jthread([promise = std::move(slow)] mutable {
// Заснуть, вызвав таймаут для потребителя
std::this_thread::sleep_for(2s);
promise.set_value();
});
// Подождать 200мс (что вызовет таймаут)
if (will_timeout.wait_for(200ms) == std::future_status::timeout) {
// Ветка таймаута
} else {
// Если таймаута не было, вызов get() не вызовет блокировку
// (в целом, это также может быть отложенная функция)
will_timeout.get();
}
