C++库std::future
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()
== falsefuture( 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
作用
- 异步操作的结果获取:
std::future
提供了一种机制,允许我们在多线程环境中安全地获取异步操作的结果。 - 隐藏异步操作的细节:
std::future
将异步操作的结果封装起来,使程序员无需关注线程同步和通信的具体实现细节。 - 线程同步:通过阻塞等待异步操作完成,
std::future
可以确保我们在继续执行其他操作之前,已经获取了所需的结果。 - 异常处理:
std::future
可以捕获异步操作中抛出的异常,并在获取结果时重新抛出,也可以在主线程中对其进行处理,从而使得异常处理更加简单。 - 提高性能:
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::ready
、std::future_status::timeout
或std::future_status::deferred
)。
注意事项
在使用std::future
时,需要注意以下几点:
std::future::get()
函数只能被调用一次。调用get()之后,std::future
对象将变为无效状态。如果需要多次访问结果,可以考虑使用std::shared_future。std::future
对象不可拷贝,但可以通过移动构造函数或移动赋值操作符进行转移。这意味着我们不能将std::future对象存储在容器中,除非使用std::shared_future或指针包装。- 当使用
std::async
时,默认情况下,任务可能会在当前线程上下文中执行。这取决于库实现和系统资源。若要确保任务在新线程中执行,可以使用std::launch::async
标志:
std::future result_future = std::async(std::launch::async, long_running_task);
- 如果std::future对象在析构时仍关联着一个有效的异步操作,且该操作尚未完成,析构函数会阻塞等待操作完成。在某些情况下,这可能导致程序死锁。为了避免这个问题,可以在析构std::future对象之前显式地调用wait()、wait_for()或wait_until()函数。
- 虽然
std::future
在获取异步任务结果和线程同步方面非常有用,但它并不能解决所有并发问题。例如,std::future
无法用于实现复杂的并发模式,如线程池、工作窃取等。对于这些高级并发需求,可能需要使用其他库或者自定义实现。 - 使用
std::promise
和std::future
时,需要确保在调用get()
之前已经设置了对应的值,否则会导致未定义的行为。这可能需要对代码进行仔细的设计和调试,以确保正确的执行顺序。 std::future
对象的生命周期需要仔细管理。如果std::future
对象被提前销毁,那么关联的异步任务可能会变得不可访问。因此,需要确保在异步任务完成之前保持std::future
对象的有效性。- 在某些情况下,使用
std::future
可能会导致性能下降。例如,当多个线程频繁地等待异步操作结果时,可能会导致线程阻塞和上下文切换开销。为了避免这个问题,可以考虑使用非阻塞的方式查询异步操作状态,如std::future::wait_for()
和std::future::wait_until()
函数。这样,我们可以在异步操作未完成时执行其他任务,提高程序的响应性和并发性能。 std::future
并不适用于所有场景。例如,它不适用于需要处理多个输入或输出结果的任务,或者需要实现动态任务依赖关系的场景。在这些情况下,可能需要寻找其他并发和同步解决方案。- 虽然
std::future
提供了异常处理机制,但需要注意的是,一旦std::future::get()
函数重新抛出异常,该异常需要在调用get()
的线程中进行捕获和处理。这意味着需要在主线程和其他线程中设置适当的异常处理策略,以确保程序的稳定性和健壮性。
其他
std::shared_future
std::shared_future
是std::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相关推荐
- C++并发编程线程间共享数据std::future和sd::promise
线程间共享数据 使用互斥锁实现线程间共享数据 为了避免死锁可以考虑std::lock()或者boost::shared_mutex 要尽量保护更少的数据 同步并发操作 C++标准库提供了一些工具 可以 ...
- C++11学习笔记-----线程库std::thread
在以前,要想在C++程序中使用线程,需要调用操作系统提供的线程库,比如linux下的<pthread.h>.但毕竟是底层的C函数库,没有什么抽象封装可言,仅仅透露着一种简单,暴力美 C++ ...
- 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 ...
- C++多线程编程(3) 异步操作类 std::future std::promise std::async
C++中提供了异步操作相关的类: 1. std::future: 异步结果的传输通道,可以很方便的获取线程函数的返回值. 在C++中,如果希望获取线程函数的返回值,就不能直接通过thread.join ...
- C++ 的 std::promise 和 std::future
介绍 编写多线程应用时,无法避免的要进行线程间数据同步/通信.std::promise 和 std::future 是 C++ 进行单向数据传递的一种方式.std::promise 是数据的输入端,s ...
- C++11之std::future对象使用说明
std::future介绍 在前面几篇文章中基本都用到thread对象,它是C++11中提供异步创建多线程的工具.但是我们想要从线程中返回异步任务结果,一般需要依靠全局变量:从安全角度看,有些不妥:为 ...
- C++ 多线程:std::future
概念 我们前面介绍的std::thread 是C++11中提供异步创建多线程的工具,只能是异步运行任务,却无法获取任务执行的结果,一般都是依靠全局对象,全局对象在多线程下是及其不安全的,为此标准库提供 ...
- C++11中std::future的使用
C++11中的std::future是一个模板类.std::future提供了一种用于访问异步操作结果的机制.std::future所引用的共享状态不能与任何其它异步返回的对象共享(与std::sha ...
- C++中标准模板库std::vector的实现
以下实现了C++标准模板库std::vector的部分实现,参考了 cplusplus. 关于C++中标准模板库std::vector的介绍和用法可以参考 https://blog.csdn.net/ ...
最新文章
- jwttoken解码_使用 JSON WEB TOKEN (jwt) 验证
- 在 Linux 下运行 ASP.NET 2.0
- 《FPGA全程进阶---实战演练》第二十一章 电源常用类型:LDO和 DCDC
- Zigbee网络架构+ZigBee的体系结构+理解zigbee节点的实现的案例+“51单片机” 和 “zigbee” 、 “cc2530芯片” 之间的关系+芯片cc2530
- 集成Jupyter notebook的工具或平台
- 灰色按钮激活程序的原理 (学习)
- EMD/EEMD 经验模态分解/集合经验模态分解
- 查看计算机网卡型号命令,win10系统 查看电脑网卡型号的设置方法
- linux sniffer 程序使用,Linux下Sniffer程序的实现
- 模拟电子技术之运算放大器
- 安装驱动显卡重启计算机,win10系统电脑安装显卡驱动后一直重启的解决方案
- 基于python实现在线听音乐(QQ音乐)
- Spring Boot:四大神器之CLI
- ab压力测试结果-简要说明
- 计算机组成原理实验写出下列微指令编码,计算机组成原理实验三.doc
- 小程序实现图片预加载(图片延迟加载)
- 推荐算法(一)——FM因式分解机
- 企业微信如何创建待办事项?
- fping 命令参考--网络工具--快速ping--windowslinux
- BLE低功耗蓝牙和传统蓝牙的五大区别
热门文章
- 原生JS的插件库jQuery
- (转载)js技巧 .
- lotus notes 闪退_帮你win7系统Lotus Notes邮箱闪退的详细方法
- c与c++中和*号的理解
- ALWAYSON删除可用性数据库,可用性副本
- Mac下最专业的视频剪辑软件,FCPX视频降噪实用教学
- mate20por3d人脸识别_华为mate30pro支持3D结构光人脸识别吗
- python函数格式化输出唐诗《锦瑟》_编程小白是这样用python把唐诗玩坏的
- java记事本字体_记事本中的字体+字形+大小设置
- RabbitMQ教程大全看这一篇就够了-java版本