std::future

  • 介绍
    • 成员函数
    • 作用
  • 使用场景
    • 异步任务
    • 并发控制
    • 结果获取
  • 用法示例
    • 使用std::async关联异步任务
    • 使用std::promise与std::future配合
    • 结果获取与异常处理
  • 注意事项
  • 其他
    • std::shared_future
    • std::future_status

介绍

std::future < T > f

std::future是C++11标准库(并发支持库)中的一个模板类,它表示一个异步操作的结果。当我们在多线程编程中使用异步任务时,std::future可以帮助我们在需要的时候获取任务的执行结果。std::future的一个重要特性是能够阻塞当前线程,直到异步操作完成,从而确保我们在获取结果时不会遇到未完成的操作。

成员函数

  • 构造函数

    • future() noexcept: 默认构造函数。构造无共享状态的 std::future 。构造后, valid() == false
    • future( future&& other ) noexcept:移动构造函数。用移动语义,以 other 的共享状态构造 std::future 。构造后 other.valid() == false 。
    • future( const future& other ) = delete : 不可复制构造 (CopyConstructible) 。
  • 析构函数 ~future();
  • operator=
    • future& operator=( future&& other ) noexcept:释放任何共享状态并移动赋值 other 的内容给 *this 。赋值后, other.valid() == false 且 this->valid() 将产生与 other.valid() 在赋值前相同的值。
    • future& operator=( const future& other ) = delete: 不可复制赋值 (CopyAssignable) 。
  • share() noexcept: 转移 *this 的共享状态到 std::shared_future 对象。多个 std::shared_future 对象可引用同一共享对象,调用后valid() == false
  • T get(): get 方法等待直至 future 拥有合法结果并(依赖于使用哪个模板)获取它。它等效地调用 wait() 等待结果。泛型模板和二个模板特化各含单个 get 版本。 get 的三个版本仅在返回类型有别。若调用此函数前 valid() 为 false 则行为未定义。释放任何共享状态。调用此方法后valid() 为 false 。
  • bool valid(): 检查future是否可以共享状态。
  • wait(): 等待结果变得可用
  • wait_for
  • wait_until

作用

  1. 异步操作的结果获取std::future提供了一种机制,允许我们在多线程环境中安全地获取异步操作的结果。
  2. 隐藏异步操作的细节std::future将异步操作的结果封装起来,使程序员无需关注线程同步和通信的具体实现细节。
  3. 线程同步:通过阻塞等待异步操作完成,std::future可以确保我们在继续执行其他操作之前,已经获取了所需的结果。
  4. 异常处理std::future可以捕获异步操作中抛出的异常,并在获取结果时重新抛出,也可以在主线程中对其进行处理,从而使得异常处理更加简单。
  5. 提高性能std::future使得我们能够更好地利用多核处理器的性能,通过并行执行任务来提高程序的执行效率。

使用场景

异步任务

当我们需要在后台执行一些耗时操作时,如文件读写、网络请求或计算密集型任务,std::future可以用来表示这些异步任务的结果。通过将任务与主线程分离,我们可以实现任务的并行处理,从而提高程序的执行效率。

并发控制

在多线程编程中,我们可能需要等待某些任务完成后才能继续执行其他操作。通过使用std::future,我们可以实现线程之间的同步,确保任务完成后再获取结果并继续执行后续操作。

结果获取

std::future提供了一种安全的方式来获取异步任务的结果。我们可以使用std::future::get()函数来获取任务的结果。此函数会阻塞当前线程,直到异步操作完成。这样,在调用get()函数时,我们可以确保已经获取到了所需的结果。如果异步操作中发生了异常,get()函数会将异常重新抛出,使得我们能够处理这些异常。


用法示例

头文件:

#include <future>

使用std::async关联异步任务

std::async是一种将任务与std::future关联的简单方法。它创建并运行一个异步任务,并返回一个与该任务结果关联的std::future对象。

#include <iostream>
#include <future>
#include <chrono>int long_running_task() {std::this_thread::sleep_for(std::chrono::seconds(3));return 42;
}int main() {std::future<int> result_future = std::async(std::launch::async, long_running_task);// 在此处执行其他操作int result = result_future.get();std::cout << "Result: " << result << std::endl;return 0;
}

使用std::promise与std::future配合

std::promise是另一种与std::future配合使用的方式。我们可以使用std::promise对象来显式地设置任务的结果,而std::future对象则用于获取这个结果。

#include <iostream>
#include <future>
#include <thread>void long_running_task(std::promise<int> result_promise) {// 执行长时间运行的任务int result = 42;// 将结果设置到promise对象中result_promise.set_value(result);
}int main() {std::promise<int> result_promise;std::future<int> result_future = result_promise.get_future();// 创建一个新线程,执行长时间运行的任务std::thread task_thread(long_running_task, std::move(result_promise));// 在此处执行其他操作int result = result_future.get();std::cout << "Result: " << result << std::endl;task_thread.join();return 0;
}

结果获取与异常处理

使用std::future::get() 函数可以获取异步任务的结果。此函数会阻塞当前线程,直到异步操作完成。如果异步操作中发生了异常,get()函数会将异常重新抛出。

// 注意:std::future::get()函数只能被调用一次。在调用get()之后,std::future对象将变为无效状态。
// 如果需要多次访问结果,可以考虑使用std::shared_future。
try {int result = result_future.get();std::cout << "Result: " << result << std::endl;
} catch (const std::exception& e) {std::cerr << "Exception caught: " << e.what() << std::endl;
} catch (...) {std::cerr << "Unknown exception caught" << std::endl;
}std::chrono::milliseconds timeout(100);
std::future_status status = result_future.wait_for(timeout);if (status == std::future_status::ready) {int result = result_future.get();std::cout << "Result: " << result << std::endl;
} else {std::cerr << "Timeout: the task is still running" << std::endl;
}

为了避免阻塞,我们可以使用std::future::wait_for()std::future::wait_until()函数等待一段时间或直到某个时刻。这些函数会返回一个std::future_status枚举值,表示异步操作的状态(std::future_status::readystd::future_status::timeoutstd::future_status::deferred)。


注意事项

在使用std::future时,需要注意以下几点:

  1. std::future::get()函数只能被调用一次。调用get()之后,std::future对象将变为无效状态。如果需要多次访问结果,可以考虑使用std::shared_future。
  2. std::future对象不可拷贝,但可以通过移动构造函数或移动赋值操作符进行转移。这意味着我们不能将std::future对象存储在容器中,除非使用std::shared_future或指针包装。
  3. 当使用std::async时,默认情况下,任务可能会在当前线程上下文中执行。这取决于库实现和系统资源。若要确保任务在新线程中执行,可以使用std::launch::async标志:

std::future result_future = std::async(std::launch::async, long_running_task);

  1. 如果std::future对象在析构时仍关联着一个有效的异步操作,且该操作尚未完成,析构函数会阻塞等待操作完成。在某些情况下,这可能导致程序死锁。为了避免这个问题,可以在析构std::future对象之前显式地调用wait()、wait_for()或wait_until()函数。
  2. 虽然std::future在获取异步任务结果和线程同步方面非常有用,但它并不能解决所有并发问题。例如,std::future无法用于实现复杂的并发模式,如线程池、工作窃取等。对于这些高级并发需求,可能需要使用其他库或者自定义实现。
  3. 使用std::promisestd::future时,需要确保在调用get()之前已经设置了对应的值,否则会导致未定义的行为。这可能需要对代码进行仔细的设计和调试,以确保正确的执行顺序。
  4. std::future对象的生命周期需要仔细管理。如果std::future对象被提前销毁,那么关联的异步任务可能会变得不可访问。因此,需要确保在异步任务完成之前保持std::future对象的有效性。
  5. 在某些情况下,使用std::future可能会导致性能下降。例如,当多个线程频繁地等待异步操作结果时,可能会导致线程阻塞和上下文切换开销。为了避免这个问题,可以考虑使用非阻塞的方式查询异步操作状态,如std::future::wait_for()std::future::wait_until()函数。这样,我们可以在异步操作未完成时执行其他任务,提高程序的响应性和并发性能。
  6. std::future并不适用于所有场景。例如,它不适用于需要处理多个输入或输出结果的任务,或者需要实现动态任务依赖关系的场景。在这些情况下,可能需要寻找其他并发和同步解决方案。
  7. 虽然std::future提供了异常处理机制,但需要注意的是,一旦std::future::get()函数重新抛出异常,该异常需要在调用get()的线程中进行捕获和处理。这意味着需要在主线程和其他线程中设置适当的异常处理策略,以确保程序的稳定性和健壮性。

其他

std::shared_future

std::shared_futurestd::future的一个变体,允许多个线程共享同一个异步操作的结果。与std::future不同,std::shared_future对象可以被拷贝,因此可以将其存储在容器中或在多个线程之间传递。此外,std::shared_future::get()函数可以被多次调用,而不会使std::shared_future对象变为无效状态。

#include <iostream>
#include <future>
#include <thread>void print_result(std::shared_future<int> result_future) {int result = result_future.get();std::cout << "Result: " << result << std::endl;
}int main() {std::promise<int> result_promise;std::shared_future<int> result_future = result_promise.get_future().share();std::thread t1(print_result, result_future);std::thread t2(print_result, result_future);result_promise.set_value(42);t1.join();t2.join();return 0;
}

std::future_status

std::future_status是一个枚举类型,表示异步操作的状态。它有三个可能的值:

  • std::future_status::ready:异步操作已完成,结果可用。
  • std::future_status::timeout:异步操作尚未完成,等待已超时。
  • std::future_status::deferred:异步操作已被延迟,尚未启动(仅当使用std::launch::deferred策略创建std::future对象时才可能出现)。

我们可以使用std::future::wait_for()std::future::wait_until()函数查询异步操作的状态,而无需阻塞当前线程。

#include <iostream>
#include <future>
#include <chrono>int long_running_task() {std::this_thread::sleep_for(std::chrono::seconds(3));return 42;
}int main() {std::future<int> result_future = std::async(std::launch::async, long_running_task);std::chrono::milliseconds timeout(1000);std::future_status status = result_future.wait_for(timeout);if (status == std::future_status::ready) {int result = result_future.get();std::cout << "Result: " << result << std::endl;} else {std::cerr << "Timeout: the task is still running" << std::endl;}// 等待任务完成,以便正确获取结果int result = result_future.get();std::cout << "Final result: " << result << std::endl;return 0;
}

在上面的示例中,我们使用了std::future::wait_for()函数来查询异步操作的状态。如果状态为std::future_status::ready,我们可以立即获取结果。否则,我们可以在等待期间执行其他任务,以提高程序的响应性和并发性能。最后,在退出main函数之前,我们会调用result_future.get()以确保正确获取异步操作的结果。

C++库std::future相关推荐

  1. C++并发编程线程间共享数据std::future和sd::promise

    线程间共享数据 使用互斥锁实现线程间共享数据 为了避免死锁可以考虑std::lock()或者boost::shared_mutex 要尽量保护更少的数据 同步并发操作 C++标准库提供了一些工具 可以 ...

  2. C++11学习笔记-----线程库std::thread

    在以前,要想在C++程序中使用线程,需要调用操作系统提供的线程库,比如linux下的<pthread.h>.但毕竟是底层的C函数库,没有什么抽象封装可言,仅仅透露着一种简单,暴力美 C++ ...

  3. C++——异步操作(std::future、std::async、std::packaged_task、std::promise)

    文章目录 一.std::future与std::async 1.基本概念 2.代码演示 二.std::future与std::packaged_task 1.基本知识 2.代码演示 三.std::fu ...

  4. C++多线程编程(3) 异步操作类 std::future std::promise std::async

    C++中提供了异步操作相关的类: 1. std::future: 异步结果的传输通道,可以很方便的获取线程函数的返回值. 在C++中,如果希望获取线程函数的返回值,就不能直接通过thread.join ...

  5. C++ 的 std::promise 和 std::future

    介绍 编写多线程应用时,无法避免的要进行线程间数据同步/通信.std::promise 和 std::future 是 C++ 进行单向数据传递的一种方式.std::promise 是数据的输入端,s ...

  6. C++11之std::future对象使用说明

    std::future介绍 在前面几篇文章中基本都用到thread对象,它是C++11中提供异步创建多线程的工具.但是我们想要从线程中返回异步任务结果,一般需要依靠全局变量:从安全角度看,有些不妥:为 ...

  7. C++ 多线程:std::future

    概念 我们前面介绍的std::thread 是C++11中提供异步创建多线程的工具,只能是异步运行任务,却无法获取任务执行的结果,一般都是依靠全局对象,全局对象在多线程下是及其不安全的,为此标准库提供 ...

  8. C++11中std::future的使用

    C++11中的std::future是一个模板类.std::future提供了一种用于访问异步操作结果的机制.std::future所引用的共享状态不能与任何其它异步返回的对象共享(与std::sha ...

  9. C++中标准模板库std::vector的实现

    以下实现了C++标准模板库std::vector的部分实现,参考了 cplusplus. 关于C++中标准模板库std::vector的介绍和用法可以参考 https://blog.csdn.net/ ...

最新文章

  1. jwttoken解码_使用 JSON WEB TOKEN (jwt) 验证
  2. 在 Linux 下运行 ASP.NET 2.0
  3. 《FPGA全程进阶---实战演练》第二十一章 电源常用类型:LDO和 DCDC
  4. Zigbee网络架构+ZigBee的体系结构+理解zigbee节点的实现的案例+“51单片机” 和 “zigbee” 、 “cc2530芯片” 之间的关系+芯片cc2530
  5. 集成Jupyter notebook的工具或平台
  6. 灰色按钮激活程序的原理 (学习)
  7. EMD/EEMD 经验模态分解/集合经验模态分解
  8. 查看计算机网卡型号命令,win10系统 查看电脑网卡型号的设置方法
  9. linux sniffer 程序使用,Linux下Sniffer程序的实现
  10. 模拟电子技术之运算放大器
  11. 安装驱动显卡重启计算机,win10系统电脑安装显卡驱动后一直重启的解决方案
  12. 基于python实现在线听音乐(QQ音乐)
  13. Spring Boot:四大神器之CLI
  14. ab压力测试结果-简要说明
  15. 计算机组成原理实验写出下列微指令编码,计算机组成原理实验三.doc
  16. 小程序实现图片预加载(图片延迟加载)
  17. 推荐算法(一)——FM因式分解机
  18. 企业微信如何创建待办事项?
  19. fping 命令参考--网络工具--快速ping--windowslinux
  20. BLE低功耗蓝牙和传统蓝牙的五大区别

热门文章

  1. 原生JS的插件库jQuery
  2. (转载)js技巧 .
  3. lotus notes 闪退_帮你win7系统Lotus Notes邮箱闪退的详细方法
  4. c与c++中和*号的理解
  5. ALWAYSON删除可用性数据库,可用性副本
  6. Mac下最专业的视频剪辑软件,FCPX视频降噪实用教学
  7. mate20por3d人脸识别_华为mate30pro支持3D结构光人脸识别吗
  8. python函数格式化输出唐诗《锦瑟》_编程小白是这样用python把唐诗玩坏的
  9. java记事本字体_记事本中的字体+字形+大小设置
  10. RabbitMQ教程大全看这一篇就够了-java版本