C++ 异步编程:std::async
、std::future
、std::packaged_task
和 std::promise
在现代 C++ 编程中,异步编程已经成为一种常见的模式。利用 C++11 引入的标准库组件 std::async
、std::future
、std::packaged_task
和 std::promise
,我们可以更方便地处理多线程任务。本文将介绍这些组件的基本用法及其应用场景,帮助你理解如何利用这些工具实现高效的异步编程。
1. std::future
和 std::promise
std::future
std::future
是一种用于获取异步计算结果的机制。它提供了一个等待异步任务完成并获取结果的方法。std::future
对象通过与 std::promise
结合使用,允许线程安全地获取异步操作的结果或异常。
基本用法:
#include <iostream>
#include <thread>
#include <future>
void async_task(std::promise<int>& prom) {
std::this_thread::sleep_for(std::chrono::seconds(2)); // 模拟耗时操作
prom.set_value(42); // 设置计算结果
}
int main() {
std::promise<int> prom;
std::future<int> fut = prom.get_future();
std::thread t(async_task, std::ref(prom)); // 使用 std::ref 传递 promise 的引用
t.detach(); // 线程分离,允许在主线程中继续执行
int result = fut.get(); // 等待异步任务完成并获取结果
std::cout << "Result: " << result << std::endl;
return 0;
}
解释:
std::promise<int>
创建一个promise
对象,用于设置值。std::future<int> fut = prom.get_future();
从promise
获取future
对象。- 在异步线程中,调用
prom.set_value(42);
设置结果。 fut.get();
阻塞当前线程,直到结果可用。
std::promise
std::promise
用于在异步操作中设置结果。它与 std::future
结合使用,以便从线程中传递结果或异常。std::promise
对象只能被设置一次,设置多次会引发异常。
基本用法:
#include <iostream>
#include <thread>
#include <future>
void async_task(std::promise<int> prom) {
prom.set_value(42); // 设置计算结果
}
int main() {
std::promise<int> prom;
std::future<int> fut = prom.get_future();
std::thread t(async_task, std::move(prom)); // 使用 std::move 转移 promise
t.join(); // 等待线程完成
int result = fut.get(); // 获取异步任务的结果(会阻塞直到结果可用)
std::cout << "Result: " << result << std::endl;
return 0;
}
解释:
std::promise<int> prom;
创建promise
对象。std::future<int> fut = prom.get_future();
获取future
对象。- 在异步线程中,通过
prom.set_value(42);
设置结果。 fut.get();
获取结果并阻塞当前线程。
2. std::packaged_task
std::packaged_task
是一个可调用对象,用于将任务的结果与 std::future
绑定。它允许你将一个普通的函数或函数对象封装为一个异步任务,并从中获取结果。
基本用法:
#include <iostream>
#include <thread>
#include <future>
int long_computation(int x) {
std::this_thread::sleep_for(std::chrono::seconds(2)); // 模拟耗时操作
return x * x;
}
int main() {
std::packaged_task<int(int)> task(long_computation); // 创建任务
std::future<int> fut = task.get_future(); // 获取 future 对象
std::thread t(std::move(task), 10); // 使用 std::move 转移任务,并传递参数
t.join(); // 等待线程完成
int result = fut.get(); // 获取异步任务的结果(会阻塞直到结果可用)
std::cout << "Result: " << result << std::endl;
return 0;
}
解释:
std::packaged_task<int(int)> task(long_computation);
创建一个任务对象,封装long_computation
函数。std::future<int> fut = task.get_future();
获取与任务关联的future
对象。std::thread t(std::move(task), 10);
将任务移动到线程中,并传递参数。fut.get();
获取任务结果。
3. std::async
std::async
是一种更高层次的异步操作工具,它可以在后台线程中异步执行函数,并返回一个 std::future
对象,用于获取结果。它比手动创建线程更简单。
基本用法:
#include <iostream>
#include <future>
#include <chrono>
int long_computation(int x) {
std::this_thread::sleep_for(std::chrono::seconds(2)); // 模拟耗时操作
return x * x;
}
int main() {
std::future<int> fut = std::async(std::launch::async, long_computation, 10); // 异步执行
// 可以在这里做其他事情
std::cout << "Doing other things while waiting for the result..." << std::endl;
int result = fut.get(); // 获取异步任务的结果(会阻塞直到结果可用)
std::cout << "Result: " << result << std::endl;
return 0;
}
解释:
std::async(std::launch::async, long_computation, 10);
异步执行long_computation
函数,并传递参数。fut.get();
获取结果并阻塞当前线程,直到结果可用。
总结
std::promise
用于设置异步操作的结果或异常。std::future
用于获取异步操作的结果或异常。std::packaged_task
封装函数为任务,并与std::future
结合使用。std::async
简化异步任务的创建和管理,自动处理线程和任务。
通过理解和使用这些 C++ 标准库组件,你可以更高效地进行异步编程,管理复杂的任务和线程操作。