std::promise 使用详解

std::promise 是 C++11 引入的并发编程工具,用于在线程间传递异步操作的结果(值或异常)。它与 std::future 配合使用,构成生产者-消费者模型:生产者线程通过 promise 设置结果,消费者线程通过关联的 future 获取结果。


核心作用

  1. 结果传递
    允许一个线程存储值或异常,另一个线程通过 future 获取。
  2. 线程同步
    future.get() 会阻塞消费者线程,直到生产者设置结果。
  3. 异常传递
    可将异常从生产者线程传递到消费者线程。

基本用法

步骤 1:创建 promise 和 future
#include <future>
#include <iostream>

int main() {
    std::promise<int> prom;          // 创建 promise 对象
    std::future<int> fut = prom.get_future(); // 获取关联的 future
    // ...
}
步骤 2:生产者线程设置值
void producer(std::promise<int>&& prom) {
    int result = 42; // 模拟计算结果
    prom.set_value(result); // 存储结果到 promise
    // 或 prom.set_exception(std::current_exception()); 传递异常
}
步骤 3:消费者线程获取值
void consumer(std::future<int>&& fut) {
    try {
        int result = fut.get(); // 阻塞直到结果就绪
        std::cout << "Result: " << result << std::endl;
    } catch (const std::exception& e) {
        std::cerr << "Exception: " << e.what() << std::endl;
    }
}
步骤 4:启动线程
int main() {
    std::promise<int> prom;
    std::future<int> fut = prom.get_future();

    std::thread producer_thread(producer, std::move(prom));
    std::thread consumer_thread(consumer, std::move(fut));

    producer_thread.join();
    consumer_thread.join();
}

关键特性

  1. 一次性使用
    • set_value()set_exception() 只能调用一次。
    • future.get() 只能调用一次(第二次会抛 std::future_error)。
  2. 移动语义
    promisefuture 不可复制,只能移动(使用 std::move)。
  3. 异常安全
    如果 promise 析构时未设置结果,future.get() 会抛 std::future_error(错误码 broken_promise)。

完整示例:计算平方

#include <iostream>
#include <future>
#include <thread>
#include <cmath>

// 生产者:计算平方
void compute_square(std::promise<double>&& prom, double x) {
    try {
        if (x < 0) throw std::domain_error("Negative input");
        double result = x * x;
        prom.set_value(result);  // 设置结果
    } catch (...) {
        prom.set_exception(std::current_exception());  // 传递异常
    }
}

int main() {
    std::promise<double> prom;
    std::future<double> fut = prom.get_future();

    double input = 4.0;
    std::thread worker(compute_square, std::move(prom), input);

    try {
        double result = fut.get();  // 阻塞等待结果
        std::cout << input << "^2 = " << result << std::endl;
    } catch (const std::exception& e) {
        std::cerr << "Error: " << e.what() << std::endl;
    }

    worker.join();
    return 0;
}

适用场景

  1. 线程池任务返回结果
    promise 与任务绑定,通过 future 获取结果。
  2. 超时控制
    结合 future.wait_for() 实现超时等待。
  3. 复杂异步操作
    多个 promise 可组合为复杂工作流(需配合 std::async 或手动管理)。

注意事项

  1. 生命周期管理
    确保 promise 存活直至结果被设置。
  2. 性能考量
    频繁创建 promise/future 可能影响性能,优先考虑线程池。
  3. 替代方案
    简单任务可用 std::async(内部自动管理 promise/future)。
### `std::future` 的作用与使用方法详解 `std::future` 是 C++11 引入的标准库组件之一,用于异步编程。它提供了一种机制,允许一个线程等待另一个线程完成任务并获取其结果。`std::future` 的核心价值在于简化异步编程的复杂性,并提供类型安全的并发控制,适用于需要结果同步、异常处理或灵活任务调度的场景[^3]。 #### 核心概念 - **合法性(Validity)**:一个 `std::future` 对象必须是合法的才能使用。合法的 `std::future` 对象只能通过调用 `std::async`、`std::promise::get_future()` 或 `std::packaged_task::get_future()` 接口构造得到。默认构造的 `std::future` 对象是不合法的,除非通过 `move` 操作从一个合法对象构造[^4]。 - **共享状态(Shared State)**:`std::future` 与一个“共享状态”相关联,该状态的生命周期至少持续到最后一个关联的 `std::future` 或 `std::shared_future` 对象被释放或销毁为止。共享状态用于存储异步任务的结果或异常信息。 #### 成员函数 `std::future` 提供了多种成员函数来操作异步任务的结果: - `get()`:阻塞当前线程,直到异步任务完成,并返回结果。如果任务抛出了异常,则 `get()` 会重新抛出该异常[^1]。 - `valid()`:检查 `std::future` 是否与某个共享状态关联。如果 `valid()` 返回 `false`,则不能调用 `get()` 或 `wait()`。 - `wait()`:阻塞当前线程,直到异步任务完成,但不返回结果[^1]。 - `wait_for()` / `wait_until()`:等待异步任务在指定时间内完成,返回状态(如 `std::future_status::ready`、`std::future_status::timeout` 等)。 #### 使用场景 `std::future` 常用于以下场景: - **异步任务并发控制**:通过 `std::async` 启动异步任务,并通过 `std::future` 获取其结果。这可以避免显式使用线程和互斥量,简化并发编程[^1]。 - **结果获取与异常处理**:`std::future` 可以安全地在多个线程之间传递结果,支持异常传播。如果异步任务抛出异常,`get()` 会重新抛出该异常,便于集中处理错误[^2]。 - **任务调度与同步**:`std::future` 可以与 `std::promise` 和 `std::packaged_task` 配合使用,实现更灵活的任务调度和同步机制。 #### 用法示例 ##### 使用 `std::async` 关联异步任务 ```cpp #include <iostream> #include <future> #include <chrono> int compute(int x) { std::this_thread::sleep_for(std::chrono::seconds(2)); return x * x; } int main() { std::future<int> result = std::async(std::launch::async, compute, 5); std::cout << "Waiting for result..." << std::endl; int value = result.get(); // 阻塞直到结果可用 std::cout << "Result: " << value << std::endl; return 0; } ``` ##### 使用 `std::promise` 与 `std::future` 配合 ```cpp #include <iostream> #include <future> #include <thread> void set_value(std::promise<int>& p) { std::this_thread::sleep_for(std::chrono::seconds(1)); p.set_value(42); } int main() { std::promise<int> p; std::future<int> f = p.get_future(); std::thread t(set_value, std::ref(p)); std::cout << "Waiting for value..." << std::endl; int value = f.get(); // 阻塞直到值被设置 std::cout << "Value: " << value << std::endl; t.join(); return 0; } ``` ##### 异常处理 ```cpp #include <iostream> #include <future> #include <stdexcept> void throw_exception() { throw std::runtime_error("An error occurred!"); } int main() { std::future<void> f = std::async(std::launch::async, throw_exception); try { f.get(); // 抛出异常 } catch (const std::exception& e) { std::cout << "Caught exception: " << e.what() << std::endl; } return 0; } ``` #### 注意事项 - **单次获取**:`std::future` 只能调用一次 `get()`,再次调用会抛出异常。如果需要多次获取结果,应使用 `std::shared_future`[^1]。 - **线程安全**:`std::future` 的 `get()` 和 `wait()` 方法是线程安全的,但其他操作(如 `valid()`)可能需要额外的同步[^1]。 - **资源管理**:确保 `std::future` 对象在异步任务完成前保持有效,否则可能导致未定义行为[^1]。 #### 其他相关类型 - **`std::shared_future`**:类似于 `std::future`,但允许多个线程同时等待同一个异步结果。适用于多个消费者需要访问同一结果的场景。 - **`std::future_status`**:表示 `std::future` 的状态,如 `std::future_status::ready`(结果已就绪)、`std::future_status::timeout`(超时)或 `std::future_status::deferred`(任务未执行)。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值