C++ 异步库
std::future && std::packaged_task
std::future
是C++11标准库中提供的用于异步计算的核心组件之一。它代表了一个可能还未完成的异步计算的结果。通过使用std::future
,开发者可以在主线程或其他线程发起一个异步操作,并能够在将来某个时刻查询操作的状态、等待操作完成或者获取操作的结果。
std::future
提供了如下主要功能:
- 异步操作结果的封装:一个
std::future
对象可以存储由异步操作产生的任何类型的结果。 - 阻塞等待:通过调用
std::future::get()
方法,当前线程可以阻塞等待异步操作完成并获取其结果。 - 检查状态:通过
std::future::valid()
、std::future::wait()
、std::future::wait_for()
、std::future::wait_until()
等方法可以检查异步操作是否已经完成。 - 共享结果:多个
std::future
对象可以关联到同一个异步操作的结果,从而允许多个线程或函数安全地访问同一份数据。 - 异常处理:如果异步操作抛出了异常,那么当尝试获取
std::future
的结果时,该异常会被重新抛出。
std::packaged_task
是C++11标准库中提供的另一种用于异步编程的工具,它将一个可调用对象(如函数、lambda表达式或仿函数)与std::future
结合在一起。通过创建一个std::packaged_task
对象,可以将任务打包起来,并且每次调用std::packaged_task::get_future()
都会得到一个与之关联的std::future
对象,这个future
可以用来获取任务完成后产生的结果。
基本使用格式如下:
std::packaged_task<ResultType(ParamTypes...)> task(Function);
std::future<ResultType> future = task.get_future();
例如:
#include <future>
#include <iostream>
// 定义一个计算平方的函数
int square(int x) {
return x * x;
}
int main() {
// 创建一个包装任务,将square函数与其绑定
std::packaged_task<int(int)> task(square);
// 获取与该任务关联的future
std::future<int> result_future = task.get_future();
// 将任务提交到另一个线程执行
std::thread worker(std::move(task), 10); // 使用std::move避免复制任务
// 主线程可以继续执行其他任务...
// 等待future的结果
int result = result_future.get();
std::cout << "The square of 10 is: " << result << std::endl;
// 确保worker线程结束
worker.join();
return 0;
}
在这个例子中,std::packaged_task
将square
函数打包,创建一个可以异步执行的任务,并通过get_future()
获取到任务完成后的结果的std::future
。之后,任务被移动到新的线程中执行,主线程通过result_future.get()
等待并获取计算结果。
std::async
std::async
用于创建异步任务的功能。它允许你在不同的线程上执行函数调用,返回一个std::future
对象,该对象可用于获取异步调用的结果。
基本使用格式如下:
std::future<ReturnType> future = std::async(std::launch::policy, Function, Args...);
-
std::launch::policy
是一个枚举类型,用于指定如何启动任务。可能的选项包括std::launch::async
(强制异步执行)和std::launch::deferred
(延迟执行,只有当获取未来对象的结果时才执行)以及默认策略(根据实现决定是立即执行还是延迟执行)。 -
Function
是要异步调用的函数或者可调用对象,可以带任意数量的参数Args...
。
例如:
#include <future>
#include <iostream>
int heavyComputation(int n) {
// 模拟耗时操作
std::this_thread::sleep_for(std::chrono::seconds(1));
return n * n;
}
int main() {
std::future<int> fut = std::async(std::launch::async, heavyComputation, 10);
std::cout << "Doing some other work..." << std::endl;
// 获取异步任务的结果,这一步可能阻塞直到结果可用
int result = fut.get();
std::cout << "The result of the computation is: " << result << std::endl;
return 0;
}
在这个例子中,heavyComputation
函数在一个单独的线程上异步执行,主线程可以继续执行其他任务,然后通过调用fut.get()
来等待并获取计算结果。
std::promise
std::promise
是C++11标准库中用于异步编程的一个组件,它与std::future
配对使用,允许在不同线程间传递和接收值。std::promise
对象可以设置(或“承诺”)一个值,而与之相关联的std::future
对象可以获取(或“期待”)这个值。
基本使用格式如下:
std::promise<TYPE> promise_obj; // 创建一个承诺对象,承诺一个TYPE类型的值
std::future<TYPE> future_obj = promise_obj.get_future(); // 从承诺对象获取一个future对象
// 在某个线程中设置承诺的值
promise_obj.set_value(VALUE);
// 在另一个线程中通过future对象获取承诺的值(可能阻塞)
TYPE value = future_obj.get();
例如:
#include <future>
#include <iostream>
int main() {
std::promise<int> promise;
std::future<int> future = promise.get_future();
// 启动一个新的线程来设置承诺的值
std::thread thread([p = std::move(promise)]() mutable {
std::this_thread::sleep_for(std::chrono::seconds(1));
p.set_value(42); // 设置承诺值为42
});
// 主线程等待并获取future的值
int result = future.get();
std::cout << "The promised value is: " << result << std::endl;
// 确保线程结束
thread.join();
return 0;
}
在这个例子中,std::promise
对象在新线程中设置了一个整数值,主线程通过与之关联的std::future
对象获取这个值。当future.get()
被调用时,若值尚未准备好,则调用线程将阻塞,直到值被设置为止。
std::shared_future
std::shared_future
是C++11标准库中的一个类,它是std::future
的共享版本,允许多个拥有者共享一个异步计算的结果。相比于std::future
,std::shared_future
可以被多个对象共享并管理,即使原始的std::future
或std::promise
对象被销毁,只要还有std::shared_future
对象存在,异步计算的结果就能继续保持有效。
std::shared_future
通常不是直接创建的,而是通过调用std::future::share()
函数从std::future
转换而来:
std::future<int> normalFuture = std::async([]{ return 42; });
std::shared_future<int> sharedFuture = normalFuture.share();
std::shared_future
同样提供了类似于std::future
的操作,如get()
来获取异步计算的结果,wait()
、wait_for()
和wait_until()
来等待结果准备就绪,以及检查状态的方法。
值得注意的是,由于涉及资源的共享,对std::shared_future
的操作应当谨慎,特别是在并发环境中,以防止数据竞争和死锁等问题。