future、shared_future、packaged_task、promise常用接口总结

1. std::future

std::future<T> 用于异步获取任务的结果,结果只能被获取一次。对象不可复制,但可移动。

关键特性
  • get() 调用后,future 状态失效(valid() 返回 false)。
  • 析构时,若关联的异步结果未就绪且是最后一个引用,可能阻塞等待结果(取决于启动策略)。
常用成员函数
  • get()
    获取结果,调用后 valid() 变为 false。若结果未就绪,阻塞当前线程。
    若任务抛异常,get() 会重新抛出该异常。

    T get(); // T 可能为 void、引用或值类型
    
  • wait()
    阻塞直到任务完成,不获取结果。

    void wait();
    
  • wait_for()
    等待指定时间,返回状态 future_statusreadytimeoutdeferred)。

    template <class Rep, class Period>
    std::future_status wait_for(const std::chrono::duration<Rep, Period>& rel_time);
    
  • wait_until()
    等待到指定时间点,返回状态 future_status

    template <class Clock, class Duration>
    std::future_status wait_until(const std::chrono::time_point<Clock, Duration>& timeout_time);
    
  • valid()
    检查是否关联有效结果(例如未调用 get())。

    bool valid() const noexcept;
    
  • share()
    转为 std::shared_future<T>,允许共享结果。

    std::shared_future<T> share();
    

2. std::shared_future

std::shared_future<T> 允许共享异步结果,可被多次调用 get()。对象可复制。

关键特性
  • get() 可多次调用,每次返回结果的副本(若 T 非引用)。
  • T 为引用类型(如 T&),需注意引用的有效性。
常用成员函数
  • get()
    返回结果副本(若 T 非引用)。若 Tvoid,无返回值。

    const T& get() const;  // T 非 void 时的返回类型可能不同
    
  • wait() / wait_for() / wait_until()
    std::future

  • valid()
    std::future


3. std::packaged_task

std::packaged_task<Function> 包装可调用对象(如函数、lambda),将其结果绑定到 std::future。对象不可复制,但可移动。

关键特性
  • 调用 operator() 后,结果被存储到关联的 future 中。
  • 若多次调用 operator() 或未关联可调用对象,抛出 std::future_error
常用成员函数
  • 构造函数
    需提供可调用对象。默认构造的 packaged_task 为空(valid() == false)。

    explicit packaged_task(Function&& f);
    
  • operator()
    执行任务并存储结果或异常。若已调用过或对象为空,抛出异常。

    void operator()(Args... args);
    
  • get_future()
    返回关联的 std::future<T>。若已调用或对象为空,抛出异常。

    std::future<T> get_future();
    
  • swap()
    交换两个 packaged_task 的内容。

    void swap(packaged_task& other) noexcept;
    
  • reset() (C++11 起)
    重置任务,允许重新绑定新的可调用对象。

    void reset();
    

4. std::promise

std::promise<T> 用于显式设置异步结果或异常,关联的 std::future 可获取结果。对象不可复制,但可移动。

关键特性
  • promise 析构前未设置结果,关联的 future 会收到 std::future_errorbroken_promise)。
  • 可设置结果或异常,但只能设置一次,重复设置抛出 std::future_error
常用成员函数
  • 构造函数
    默认构造的 promise 有效。移动构造函数允许转移所有权。

    promise();
    promise(promise&& other) noexcept;
    
  • set_value()
    设置结果。若 Tvoid,无参调用。

    void set_value(const T& value);
    void set_value(T&& value);
    void set_value(); // 当 T 为 void 时
    
  • set_exception()
    设置异常指针(如捕获的异常通过 std::current_exception())。

    void set_exception(std::exception_ptr p);
    
  • set_value_at_thread_exit()
    设置结果,但延迟到当前线程退出时通知 future

    void set_value_at_thread_exit(const T& value);
    
  • set_exception_at_thread_exit()
    类似 set_value_at_thread_exit,但设置异常。

    void set_exception_at_thread_exit(std::exception_ptr p);
    
  • get_future()
    返回关联的 std::future<T>,只能调用一次。

    std::future<T> get_future();
    
  • swap()
    交换两个 promise 的内容。

    void swap(promise& other) noexcept;
    

总结对比

组件核心功能是否可复制是否可移动结果获取次数特殊行为
std::future单次获取异步结果一次get() 后失效,析构可能阻塞
std::shared_future共享异步结果多次get() 返回副本或引用
std::packaged_task包装可调用对象,绑定结果到 future一次调用 operator() 后结果就绪
std::promise显式设置结果或异常一次未设置结果时析构会触发 broken_promise,可设置延迟通知

关键注意事项

  1. 异常传递:所有组件的 get() 会传递任务中抛出的异常。
  2. 有效性检查:调用 get_future()get()set_value() 前需确保对象有效(如 valid() 返回 true)。
  3. 线程安全:除 std::shared_futureconst 成员函数外,其他组件的方法通常不保证线程安全。
  4. 移动语义std::futurestd::packaged_taskstd::promise 支持移动语义,避免复制。
  5. 生命周期管理:确保 promisepackaged_task 的生命周期长于关联的 future 操作,防止悬空引用。
### shared_future 的基本概念 `std::shared_future` 是 C++11 引入的一种机制,用于处理异步操作的结果。与 `std::future` 不同的是,`std::shared_future` 允许在多个线程中多次获取结果。这意味着它可以被用来在多个线程之间共享异步操作的结果,而不会导致状态无效的问题[^2]。 ### shared_future造函数 `std::shared_future` 提供了多个造函数,包括但不限于: - 默认造函数 `shared_future()`,创建一个不持有任何异步状态的 `shared_future` 实例。 - 拷贝造函数 `shared_future(const shared_future& other)`,从另一个 `shared_future` 实例复制异步状态。 - 移动造函数 `shared_future(shared_future&& other)`,从另一个 `shared_future` 实例移动异步状态。 - 从 `std::future` 移动造 `shared_future(std::future<T>&& other)`,将 `std::future` 的异步状态转移到 `shared_future` 中[^1]。 ### shared_future 的使用示例 下面是一个简单的 `std::shared_future` 使用示例,展示了如何在一个异步操作完成后,在多个线程中获取该操作的结果: ```cpp #include <iostream> #include <future> #include <thread> void print_result(std::shared_future<int> result) { std::cout << "Result is " << result.get() << std::endl; } int main() { std::promise<int> p; std::shared_future<int> f = p.get_future(); std::thread t1(print_result, f); std::thread t2(print_result, f); // 设置值 p.set_value(42); // 等待线程完成 t1.join(); t2.join(); return 0; } ``` 在这个例子中,`std::promise` 创建了一个异步操作,并通过 `get_future` 方法获取了一个 `std::shared_future`。然后,这个 `std::shared_future` 被传递给了两个线程,这两个线程都调用了 `get` 方法来获取结果。由于使用了 `std::shared_future`,即使在两个线程中调用 `get` 方法,也不会导致状态无效的问题[^2]。 ### shared_future 的注意事项 - 当从 `std::future` 创建 `std::shared_future` 时,原始的 `std::future` 将失去对异步状态的所有权,不能再通过 `std::future` 获取结果。 - `std::shared_future` 的 `get` 方法可以被多次调用,每次都会返回相同的结果或异常。 - 在多线程环境中使用 `std::shared_future` 时,确保所有线程都完成了对 `get` 方法的调用之后再销毁 `std::shared_future` 对象,以避免悬挂指针或引用的问题[^3]。 ### shared_futurepromise 的关系 `std::promise` `std::future` 之间的关系类似于生产者消费者的关系。`std::promise` 用于设置值,而 `std::future` 用于获取这些值。当需要在多个线程中共享异步操作的结果时,可以通过 `std::future` 的 `share` 方法获得一个 `std::shared_future`,从而允许多个线程安全地访问同一个异步结果[^4]。 ### shared_future 的线程安全性 `std::shared_future` 的设计考虑了线程安全性。当多个线程同时调用 `get` 方法时,它们能够安全地获取异步操作的结果,而不会引发数据竞争或其他并发问题。这是因为 `std::shared_future` 内部的实现确保了对共享状态的访问是线程安全的[^2]。 ### shared_future 的性能考量 虽然 `std::shared_future` 提供了方便的多线程间共享异步结果的能力,但在某些情况下可能需要考虑其性能影响。由于 `std::shared_future` 需要维护额外的状态信息以支持多线程访问,因此相比 `std::future` 可能会有轻微的性能开销。在性能敏感的应用中,应仔细评估是否确实需要使用 `std::shared_future` 并考虑其他可能的优化策略。 ### shared_future 的高级用法 除了基本的异步结果共享外,`std::shared_future` 还可以与其他 C++ 标准库特性结合使用,如 `std::async` `std::packaged_task`,以实现更复杂的并发模式。例如,可以使用 `std::async` 创建异步任务,并通过 `std::shared_future` 在多个线程中等待任务完成并获取结果。这种模式非常适合需要并行处理多个任务并最终汇总结果的场景[^2]。 ### shared_future 的异常处理 `std::shared_future` 支持异常处理,这意味着如果异步操作抛出了异常,那么这个异常可以通过 `get` 方法捕获。当调用 `get` 方法时,如果异步操作已经抛出了异常,那么 `get` 方法将重新抛出该异常。这对于在多个线程中统一处理错误情况非常有用[^2]。 ### shared_future 的生命周期管理 正确管理 `std::shared_future` 的生命周期对于确保程序的稳定性正确性至关重要。当不再需要访问异步结果时,应及时释放 `std::shared_future` 对象,以便系统可以回收相关资源。特别是在使用 `std::shared_ptr` 管理 `std::shared_future` 的情况下,需要注意避免循环引用导致的内存泄漏[^2]。 ### shared_future 的调试技巧 调试涉及 `std::shared_future` 的并发程序时,可以采用以下几种技巧: - 使用日志记录每个线程调用 `get` 方法的时间点,帮助理解异步操作的实际执行顺序。 - 利用调试器的条件断点功能,在特定条件下暂停程序执行,以便检查异步状态。 - 对于复杂的并发逻辑,考虑编写单元测试来验证 `std::shared_future` 的行为是否符合预期,尤其是在异常处理资源释放方面[^2]。 ### shared_future 的最佳实践 为了有效地使用 `std::shared_future`,建议遵循以下最佳实践: - 在需要多线程共享异步结果的情况下优先选择 `std::shared_future`。 - 尽量减少对 `get` 方法的调用次数,特别是在性能关键路径上。 - 当不再需要访问异步结果时,及时释放 `std::shared_future` 对象,以释放占用的资源。 - 在设计并发程序时,充分考虑异常处理资源管理,确保程序的健壮性可靠性。 ### shared_future 的替代方案 尽管 `std::shared_future` 是 C++ 标准库中处理异步操作的强大工具,但在某些特定场景下,可能存在更适合的选择。例如,对于需要高度定制化异步行为的应用,可以考虑使用第三方库提供的异步框架,这些框架往往提供了更加丰富灵活的功能。此外,对于简单的同步需求,直接使用 `std::mutex` `std::condition_variable` 可能更为直观高效。 ### shared_future 的局限性 尽管 `std::shared_future` 提供了许多有用的功能,但也存在一些局限性: - `std::shared_future` 的实现依赖于具体的编译器标准库实现,不同平台上的行为可能会有所不同。 - 对于非常简单的应用场景,使用 `std::shared_future` 可能显得过于重量级。 - 在某些情况下,`std::shared_future` 的性能可能不如手动管理的同步机制[^2]。 ### shared_future 的未来展望 随着 C++ 标准的不断发展,`std::shared_future` 的功能性能也在持续改进。未来的 C++ 标准可能会引入新的特性,进一步增强 `std::shared_future` 的灵活性效率。开发者应密切关注 C++ 标准的发展动态,以便及时利用最新的语言特性优化成果。 ### shared_future 的常见问题解答 #### Q: 如何从 `std::future` 创建 `std::shared_future`? A: 可以通过调用 `std::future` 的 `share` 方法来创建 `std::shared_future`。这将转移 `std::future` 的所有权,使其不能再用于获取结果。 #### Q: `std::shared_future` 的 `get` 方法会多次计算任务吗? A: 不会。`std::shared_future` 的 `get` 方法只会计算一次任务,之后的所有调用都将返回相同的结果或异常。 #### Q: 如何确保 `std::shared_future` 在多线程环境中的正确使用? A: 确保所有线程都完成了对 `get` 方法的调用之后再销毁 `std::shared_future` 对象,以避免悬挂指针或引用的问题。 #### Q: `std::shared_future` 是否支持异常处理? A: 是的,`std::shared_future` 支持异常处理。如果异步操作抛出了异常,那么这个异常可以通过 `get` 方法捕获[^2]。 #### Q: `std::shared_future` 的生命周期应该如何管理? A: 当不再需要访问异步结果时,应及时释放 `std::shared_future` 对象,以便系统可以回收相关资源。特别是在使用 `std::shared_ptr` 管理 `std::shared_future` 的情况下,需要注意避免循环引用导致的内存泄漏。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值