基本概念
异步操作:指的是不会立即完成,而是会在将来的某个时间点完成的操作。在 C++ 中,异步操作可以通过多种方式实现,比如使用 std::async、std::thread 配合 std::promise/std::future,或者第三方库如 Boost.Asio。
一、std::future
std::future:是一个模板类,用于表示异步操作的结果。可以通过 std::future 的成员函数来查询异步操作是否完成,等待异步操作完成,并获取其结果。
常用函数:
1. get()
功能:阻塞当前线程,直到与 std::future对象关联的异步操作完成,并返回异步操作的结果。如果异步操作抛出了异常,get() 会重新抛出该异常。
注意:get()方法只能被调用一次。调用后,std::future 对象将变为无效状态。
2. wait()
功能:阻塞当前线程,直到与std::future 对象关联的异步操作完成。它不返回任何结果,也不抛出异步操作中发生的异常(如果有的话)
3. wait_for(duration)
功能:尝试阻塞当前线程,直到与 std::future对象关联的异步操作完成或指定的时间间隔过去。
- 如果异步操作在指定时间内完成,则返回std::future_status::ready;
- 如果时间间隔过去但异步操作尚未完成,则返回std::future_status::timeout;
- 如果 std::future对象关联的共享状态已经无效(例如,由于调用了get()),则返回std::future_status::deferred_no_state。 参数:duration是一个时间段,指定等待的最大时间。
4. wait_until(time_point)
功能:与 wait_for类似,但它是基于绝对时间点而不是时间段来等待。
- 如果异步操作在指定的时间点之前完成,则返回std::future_status::ready;
- 如果时间点到达但异步操作尚未完成,则返回std::future_status::timeout;
- 如果 std::future对象关联的共享状态已经无效,则返回std::future_status::deferred_no_state。参数:time_point是一个时间点,指定等待的截止时间。
5. valid()
功能:检查 std::future 对象是否关联了一个有效的共享状态。
如果std::future 对象是由默认构造函数创建的,或者其共享状态已经被 get() 或 wait() 消耗,则返回 false;否则返回 true。
6. share()
功能:将 std::future 对象的共享状态转移到一个新的std::shared_future 对象中。这使得多个 std::shared_future 对象可以引用同一个异步操作的结果。
调用share() 后,原 std::future 对象将不再有效(即 valid() 返回 false)。
二、std::async
std::async 是 C++11 引入的一个函数模板,它提供了一种启动异步任务的方式。当你需要并行地执行某些操作,但又不想直接管理线程(例如,通过 std::thread)时,std::async 是一个很好的选择。它允许你以非常简洁的方式启动一个异步任务,并通过返回的 std::future 对象来查询任务的状态和获取其结果。
函数原型
template<class Fn, class... Args>
future<typename std::result_of<Fn(Args...)>::type> async(std::launch policy, Fn&& fn, Args&&... args);
- Fn:可调用对象的类型,比如函数、lambda表达式、函数对象等。
- Args…:传递给可调用对象的参数类型列表。
- std::launch policy:一个启动策略,用于指示std::async 如何执行任务。常用的启动策略包括std::launch::async(尽可能异步地执行任务)和std::launch::deferred(延迟执行,直到调用future::get 或future::wait)。注意,从C++17开始,启动策略的参数是可选的,且不再推荐显式指定(因为编译器可以优化选择)。
- 返回类型:一个std::future 对象,该对象与异步操作的结果相关联。std::future 的模板参数是可调用对象返回类型的推导。
代码示例:
#include <iostream>
#include <future>
// 假设的 do_some_work 函数,它接受两个整数参数并返回它们的和
int do_some_work(int x, int y) {
// 这里不实际进行任何耗时操作,只是为了演示
return x + y;
}
int main() {
// 使用 std::async 异步执行 do_some_work,并传递两个参数
//std::future<int> result = std::async(std::launch::async, do_some_work, 3, 4);
auto result = std::async(std::launch::async, do_some_work, 3, 4);
// 在这里可以执行其他任务,而不会阻塞等待 do_some_work 完成
// 等待异步任务完成并获取结果
std::cout << "The result is " << result.get() << std::endl; // 输出: The result is 7
return 0;
}