(简明版)std::promise与std::future/shared_future使用示例

 可以总结下面几个步骤步骤2和3的顺序大多情况可以调换

  1. 创建promisefuture对象开始是通过创建一个std::promise对象。然后可以从这个promise获取返回一个std::future对象,返回的对象可以拷贝到创建的future对象。

  2. (也可以为step3)设置值或异常通过promiseset_value方法设置有效的结果,或者使用set_exception方法设置一个异常(也可以用一个自定义的默认构造对象作为异常值)。这些操作定义了异步操作的最终输出。

  3. (也可以为step2)关联promisefuture通过promise对象的get_future方法获取一个std::future对象。这一步确实可以在set_value之前或之后进行,但通常在设置值之前获取future,这样可以确保当值被设置时,future已经准备好来接收这个值。

  4. 获取结果:通过future对象的get方法来获取promise中设置的结果。如果结果尚未被设置,调用get会阻塞当前线程,直到promise的值被设置。对于std::future,一旦调用了get方法,该future对象就不能再用于获取结果了,对于std::shared_future,则可以多次调用get,每次都返回相同的结果。

  5. future对象的拷贝行为:这里稍要区分std::futurestd::shared_future

    • 对于std::future,它不支持拷贝操作,只能被移动。因此,不能简单地通过拷贝std::future对象来访问相同的结果。一旦std::future的结果被获取,它就处于无效状态。
    • 对于std::shared_future,它允许拷贝,并且拷贝之后的所有std::shared_future对象确实访问的是相同的内存中的结果,允许多次调用get方法获取结果。

 示例代码如下:

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

void asyncTask(std::promise<int>&& prom) {
    std::this_thread::sleep_for(std::chrono::seconds(2)); // 模拟耗时操作
    prom.set_value(42); // 设置promise的结果
}

int main() {
    std::promise<int> prom; // 创建一个promise对象
    std::future<int> fut = prom.get_future(); // 从promise获取future对象

    std::thread th(asyncTask, std::move(prom)); // 启动一个异步任务

    // 在等待结果时,可以做一些其他的事情...
    std::cout << "Waiting for the result..." << std::endl;

    int result = fut.get(); // 获取异步操作的结果,如果尚未准备好会阻塞在这里
    std::cout << "Result from async task: " << result << std::endl;

    th.join(); // 等待异步任务结束

    // 演示std::shared_future的能力
    std::shared_future<int> sharedFut = std::async(std::launch::async, []() -> int {
        return 88;
    });

    // 拷贝shared_future,并从多个拷贝中获取相同的结果
    auto sharedFutCopy1 = sharedFut;
    auto sharedFutCopy2 = sharedFut;
    
    std::cout << "Result from sharedFut: " << sharedFut.get() << std::endl;
    std::cout << "Result from sharedFutCopy1: " << sharedFutCopy1.get() << std::endl;
    std::cout << "Result from sharedFutCopy2: " << sharedFutCopy2.get() << std::endl;

    return 0;
}

### std::shared_futurestd::future 的主要区别 #### 1. **所有权模型** `std::future` 表示单次获取的结果,它遵循独占所有权模型。一旦 `std::future` 的结果被提取(即调用了 `.get()` 方法),该对象就变得无效,无法再次调用 `.get()` 提取结果[^2]。 相比之下,`std::shared_future` 支持共享所有权模型。它可以允许多个线程安全地访问同一个异步操作的结果,并且可以多次调用 `.get()` 来检索结果而不会使对象失效[^3]。 --- #### 2. **转换方式** `std::shared_future` 可以通过两种方式创建: - 隐式从 `std::future` 转换而来; - 显式调用 `std::future::share()` 方法来生成一个 `std::shared_future` 实例。 在这两种情况下,原始的 `std::future` 对象都会失去其有效性,不能再用于任何进一步的操作。 --- #### 3. **适用场景** 当只有一个线程需要访问异步操作的结果时,使用 `std::future` 就足够了。然而,如果多个线程都需要访问同一异步操作的结果,则应考虑使用 `std::shared_future`,因为它允许多个线程安全地共享和重复读取结果[^1]。 以下是展示两者区别的代码示例: ```cpp #include <iostream> #include <thread> #include <future> // 模拟耗时任务 int task() { std::this_thread::sleep_for(std::chrono::seconds(2)); return 42; } int main() { // 创建 futureshared_future std::promise<int> promise; auto future = promise.get_future(); auto sharedFuture = future.share(); // 启动新线程并传递 shared_future std::thread t([&]() { try { std::cout << "Thread ID: " << std::this_thread::get_id() << ", Result: " << sharedFuture.get() << "\n"; } catch (const std::exception& e) { std::cerr << "Exception caught in thread: " << e.what() << "\n"; } }); // 主线程也尝试获取结果 try { promise.set_value(task()); std::cout << "Main Thread, Result: " << sharedFuture.get() << "\n"; } catch (const std::exception& e) { std::cerr << "Exception caught in main: " << e.what() << "\n"; } t.join(); return 0; } ``` 在这个例子中,主线程和子线程都可以独立地调用 `sharedFuture.get()` 并获得相同的结果,这展示了 `std::shared_future` 的优势。 --- #### 4. **性能开销** 由于 `std::shared_future` 允许共享状态,因此它的实现可能涉及额外的同步机制(如原子变量或互斥锁)。这意味着相比于 `std::future`,`std::shared_future` 在某些情况下可能会带来轻微的性能损失。 --- ### 总结 | 特性 | `std::future` | `std::shared_future` | |---------------------|----------------------------------------|------------------------------------------| | 所有权模型 | 独占 | 共享 | | 是否可多次调用 `.get()` | 不支持 | 支持 | | 使用场景 | 单一线程访问 | 多线程共享 | | 性能 | 较高 | 略低(因同步需求) | --- 问题
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值