Daily bit(e) C++. std::promise, std::future

Добавлено 15 апреля 2026 в 18:44

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

Daily bit(e) C++

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();
}

Пример на Compiler Explorer

Теги

C++ / CppDaily bit(e) C++МногопоточностьПрограммирование