packaged_task 、future知识点
packaged_task 、future知识点
以下是对 packaged_task
和 future
的详细解释,尽量简单易懂并结合例子说明:
1. packaged_task
基本概念:
packaged_task
是一个类模板,它将一个可调用对象(如函数、函数对象、lambda 表达式等)和一个future
关联起来。它可以将可调用对象的结果存储在future
中,以便在将来的某个时间点获取结果。- 可以将
packaged_task
看作是一个任务包装器,它包装了一个任务,并允许你在另一个线程中执行该任务,同时提供一种机制,让你可以在其他地方获取该任务的结果。
使用示例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
int add(int a, int b) {
return a + b;
}
int main() {
// 将函数 add 包装在 packaged_task 中
std::packaged_task<int(int, int)> task(add);
// 获取与 packaged_task 关联的 future
std::future<int> result = task.get_future();
// 将 packaged_task 放到另一个线程中执行
std::thread t(std::move(task), 3, 4);
// 等待结果
int sum = result.get();
std::cout << "The sum is: " << sum << std::endl;
t.join();
return 0;
}- 首先,使用
std::packaged_task<int(int, int)> task(add);
将add
函数包装在packaged_task
中。 - 然后,通过
task.get_future()
获取与之关联的future
对象,这个future
用于存储add
函数的执行结果。 - 启动一个新线程
std::thread t(std::move(task), 3, 4);
,并将task
移动到该线程中执行。这里使用std::move
是因为packaged_task
是不可复制的,只能移动。 - 最后,通过
result.get()
等待并获取结果。
- 首先,使用
2. future
基本概念:
future
是一个类模板,提供了一种访问异步操作结果的机制。它可以表示一个可能尚未完成的操作,并允许你等待该操作完成并获取结果。- 当你调用
future
的get()
方法时,会阻塞当前线程,直到关联的操作完成并返回结果。
使用示例(继续上面的例子):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
int add(int a, int b) {
std::this_thread::sleep_for(std::chrono::seconds(2)); // 模拟耗时操作
return a + b;
}
int main() {
std::packaged_task<int(int, int)> task(add);
std::future<int> result = task.get_future();
std::thread t(std::move(task), 3, 4);
std::cout << "Waiting for the result..." << std::endl;
// 阻塞等待结果
int sum = result.get();
std::cout << "The sum is: " << sum << std::endl;
t.join();
return 0;
}- 在这个例子中,
add
函数可能是一个耗时操作,我们通过std::this_thread::sleep_for(std::chrono::seconds(2));
来模拟。 result.get()
会阻塞main
线程,直到add
函数执行完成并将结果存储在future
中,然后返回结果。
- 在这个例子中,
3. async
函数与 packaged_task
和 future
的关系
async函数是一个更高级的接口,它会自动将一个可调用对象包装在packaged_task 中,并返回一个future对象,使代码更简洁。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
int add(int a, int b) {
std::this_thread::sleep_for(std::chrono::seconds(2));
return a + b;
}
int main() {
std::future<int> result = std::async(std::launch::async, add, 3, 4);
std::cout << "Waiting for the result..." << std::endl;
int sum = result.get();
std::cout << "The sum is: " << sum << std::endl;
return 0;
}std::async(std::launch::async, add, 3, 4);
会在另一个线程中异步执行add
函数,并将结果存储在future
中。- 你可以使用
std::launch::deferred
参数来延迟执行,直到调用result.get()
时才开始执行任务。
4. 异常处理
如果 packaged_task 中的可调用对象抛出异常,该异常会被存储在 future中。当你调用 future的get()方法时,异常会被重新抛出。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
int divide(int a, int b) {
if (b == 0) {
throw std::runtime_error("Division by zero");
}
return a / b;
}
int main() {
std::packaged_task<int(int, int)> task(divide);
std::future<int> result = task.get_future();
std::thread t(std::move(task), 5, 0);
try {
int quotient = result.get();
std::cout << "The quotient is: " << quotient << std::endl;
} catch (const std::exception& e) {
std::cerr << "Exception: " << e.what() << std::endl;
}
t.join();
return 0;
}- 当
divide
函数中b
为 0 时,会抛出异常。 - 调用
result.get()
时,异常会被捕获并处理。
- 当
总结
packaged_task
:- 是一个任务包装器,将可调用对象和
future
关联,可在另一个线程中执行任务并存储结果。 - 可通过
get_future()
获取关联的future
对象。
- 是一个任务包装器,将可调用对象和
future
:- 用于获取异步操作的结果,调用
get()
会阻塞线程,直到结果可用。 - 可处理异常,存储关联任务抛出的异常并在
get()
时重新抛出。
- 用于获取异步操作的结果,调用
packaged_task
和 future
是 C++ 中进行异步编程和任务管理的重要工具,它们使你能够方便地在不同线程中执行任务并获取结果,同时处理异常,实现并发和并行计算
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 Darlingの妙妙屋!
评论