c++ packaged task 使用详解
std::packaged_task
-
头文件
#include <future>
。 -
类模板,模板参数为函数签名,定义如下:
template<class R, class ...Args> class packaged_task<R(Args...)>;
-
作用:
- 将 future 对象与任何可调用目标(函数、 lambda 表达式、 bind 表达式或其他函数对象)封装为一个异步任务,当执行该任务时(一般为异步执行),会调用内部关联的可调用目标,并将返回值或者调用过程中抛出的异常保存于 future 中,并令 future 准备就绪;
- 一般用于将函数封装成异步任务,而不是直接创建线程。它常常与 std::thread、std::async 等结合使用,以支持更灵活的异步编程模型;
-
使用方法:
- 创建一个 std::packaged_task 对象;
- 调用 packaged_task 对象的 get_future() 方法,获取与任务关联的 std::future 对象,用于获取任务的结果或异常;
- 将 packaged_task 对象作为参数传递给一个线程、线程池或其他异步执行方式,以便在后台执行任务;
- 在需要的时候,通过 std::future 对象的 get() 方法获取异步任务的结果,或者通过其他方法获取任务的状态和控制任务的行为;
std::packaged_task 成员函数
get_future
:返回与调用目标相关联的 future 对象,对于每一个 packaged_task,只能调用一次。make_ready_at_thread_exit
:相当于直接调用内部的可调用对象,只有在调用该方法的线程结束并且所有线程局部对象被销毁后,与之关联的 future 才会准备就绪。reset
:重置状态,抛弃先前执行的结果。
std::packaged_task 使用例子
#include <cstdio>
#include <cmath>
#include <thread>
#include <future>
#include <functional>
int f(int x, int y) { return std::pow(x, y); }
void task_lambda()
{
std::packaged_task<int(int, int)> task([](int a, int b) {return std::pow(a, b);});
std::future<int> result = task.get_future();
task(2, 9);
printf("task lambda, result is %d\n", result.get());
}
void task_bind()
{
std::packaged_task<int()> task(std::bind(f, 2, 11));
std::future<int> result = task.get_future();
task();
printf("task bind, result is %d\n", result.get());
}
void task_thread()
{
std::packaged_task<int(int, int)> task(f);
std::future<int> result = task.get_future();
std::thread task_td(std::move(task), 2, 10);
task_td.join();
printf("task thread, result is %d\n", result.get());
}
int main()
{
task_lambda();
task_bind();
task_thread();
}
make_ready_at_thread_exit 使用例子
#include <cstdio>
#include <chrono>
#include <functional>
#include <future>
#include <iostream>
#include <thread>
#include <utility>
void worker(std::future<void>& output)
{
std::packaged_task<void(bool&)> my_task{ [](bool& done) { done = true; } };
auto result = my_task.get_future();
bool done = false;
// 立即执行任务
my_task.make_ready_at_thread_exit(done);
// 函数已执行完成,done 已为 true
printf("worker, done is %d\n", done);
// 线程并未结束,局部对象仍未销毁,future 仍处于未就绪状态
auto status = result.wait_for(std::chrono::seconds(0));
if (status == std::future_status::timeout) {
printf("worker, result is not ready\n");
}
output = std::move(result);
}
int main()
{
std::future<void> result;
// 开启线程,执行任务
std::thread{worker, std::ref(result)}.join();
// 线程结束,future 转为就绪状态
auto status = result.wait_for(std::chrono::seconds(0));
if (status == std::future_status::ready) {
printf("main, result is ready\n");
}
return 0;
}
reset 使用例子
#include <cstdio>
#include <cmath>
#include <future>
int main()
{
std::packaged_task<int(int,int)> task([](int a, int b) {return std::pow(a, b);});
std::future<int> result = task.get_future();
task(2, 9);
printf("2^9 = %d\n", result.get());
task.reset();
result = task.get_future();
task(2, 10);
printf("2^10 = %d\n", result.get());
}