std::packaged_task
概述
std::packaged_task
是 C++11 引入的标准库模板类,用于包装一个可调用对象(如函数、lambda 表达式、函数对象等),使其能够与 std::future
协同工作。
简单来说,它将一个任务(可调用对象)包装起来,并允许你获取该任务的执行结果,这样你可以在一个线程中执行任务,并在另一个线程中获取其结果。
std::packaged_task
与 std::future
和 std::promise
一起,提供了异步任务执行和结果传递的功能。
基本功能
- 包装可调用对象:通过
std::packaged_task
包装一个函数或可调用对象,类似于把任务“打包”起来。 - 异步执行任务:将
packaged_task
对象交由线程执行,异步地处理任务。 - 获取任务结果:通过关联的
std::future
对象,获取异步任务的结果。
用法和示例
1. 基本用法
下面是一个使用 std::packaged_task
包装函数并在不同线程中执行任务的简单示例:
#include <iostream>
#include <future>
#include <thread>
#include <chrono>
// 一个简单的函数,用于计算整数平方
int square(int x) {
std::this_thread::sleep_for(std::chrono::seconds(2)); // 模拟耗时操作
return x * x;
}
int main() {
// 创建一个 std::packaged_task,包装 square 函数
std::packaged_task<int(int)> task(square);
// 获取关联的 std::future 对象,用于获取任务结果
std::future<int> result = task.get_future();
// 将任务交给一个线程异步执行
std::thread t(std::move(task), 5); // 传递参数5给square函数
t.detach(); // 分离线程
// 在主线程中继续做其他事情
std::cout << "Doing some work in the main thread..." << std::endl;
// 获取任务的返回值,等待任务执行完成
std::cout << "The result of square(5) is: " << result.get() << std::endl;
return 0;
}
2. 逐步解析:
-
创建
packaged_task
:std::packaged_task<int(int)> task(square);
创建一个packaged_task
,该任务包装了square
函数,函数的返回值类型为int
,接受一个int
参数。
-
获取
future
对象:std::future<int> result = task.get_future();
获取与packaged_task
关联的std::future
对象,未来可以通过该future
来获取任务的结果。
-
异步执行任务:
std::thread t(std::move(task), 5);
创建一个线程并异步执行任务,传递参数5
给square
函数。
-
等待结果:
result.get()
用于获取任务的结果。这会阻塞主线程,直到任务完成并返回值。
-
分离线程:
t.detach();
分离线程,让任务在后台运行,主线程继续执行。
3. 使用 Lambda 表达式与 std::packaged_task
你可以使用 Lambda 表达式来包装任务:
#include <iostream>
#include <future>
#include <thread>
int main() {
// 使用 lambda 表达式创建 packaged_task
std::packaged_task<int(int, int)> task([](int a, int b) {
return a + b;
});
// 获取 future 对象
std::future<int> result = task.get_future();
// 在新线程中异步执行
std::thread t(std::move(task), 10, 20);
t.detach();
// 等待结果
std::cout << "The result is: " << result.get() << std::endl;
return 0;
}
在这个例子中,Lambda 表达式 [ ](int a, int b) { return a + b; }
被传递给 packaged_task
,并在新线程中执行,主线程通过 result.get()
获取任务的返回值。
std::packaged_task
的常用成员函数
-
get_future()
:
获取与packaged_task
关联的std::future
对象,用于获取异步任务的结果。 -
operator()
:
调用packaged_task
,执行其中的任务。可以通过在新的线程中调用std::move(task)
来异步执行。 -
构造函数:
包装一个可调用对象,允许异步调用并获取返回结果。
与 std::async
和 std::thread
的区别
-
std::packaged_task
与std::future
:
std::packaged_task
和std::future
联合使用时,更加灵活,能够包装任意可调用对象并传递给线程或异步任务,用户可以显式控制任务的启动时间。 -
std::async
:
std::async
自动将任务放在后台线程中执行,返回std::future
,适合快速执行简单的异步任务,但不如packaged_task
灵活。 -
std::thread
:
std::thread
只是单纯的启动一个线程,无法直接获取线程执行的返回结果。而std::packaged_task
能与std::future
结合,使得结果可以通过future
在主线程中获取。
总结
std::packaged_task
用于包装一个可调用对象,使其可以异步执行,并通过std::future
获取其返回值。std::packaged_task
适合在异步任务管理中灵活控制任务的执行,与std::future
、std::thread
和std::async
配合使用时能够轻松管理异步操作。