C++异步编程:完整实践指南
C++异步编程是一种允许并行执行多个任务而不阻塞主执行流程的方法。与同步代码中每个操作等待前一个操作完成不同,异步代码可以启动耗时操作(输入输出、网络请求、计算),并在这些操作后台完成的同时继续执行其他任务。这对于创建响应式应用程序至关重要,尤其是在游戏行业、Web服务器和实时系统中。
在本文中,我们将通过实践讲解C++异步编程:从经典的std::async和std::future机制到现代的C++20协程。您将学习如何正确使用这些工具,避免常见错误,并创建高效的异步系统。
1. 异步基础:std::async和std::future
C++11标准库提供了一种启动异步任务的简单方法——std::async函数和std::future类。std::async在单独的线程(或线程池)中启动一个函数,并返回包含执行结果的std::future。
示例1:基本异步任务启动
#include <iostream>#include <future>#include <thread>#include <chrono>
int longComputation(int n) { std::this_thread::sleep_for(std::chrono::seconds(2)); return n * n;}
int main() { std::cout << "启动异步任务..." << std::endl; std::future<int> result = std::async(std::launch::async, longComputation, 10);
// 任务执行期间,可以执行其他工作 std::cout << "主线程继续工作..." << std::endl; std::this_thread::sleep_for(std::chrono::seconds(1));
// 获取结果(如果任务尚未完成,则阻塞线程) int value = result.get(); std::cout << "结果: " << value << std::endl; return 0;}重要事项:
std::launch::async保证在单独线程中启动。result.get()阻塞当前线程直到获取结果。- 如果不调用
get(),std::future的析构函数可能会阻塞直到任务完成。
示例2:异步任务中的异常处理
#include <iostream>#include <future>#include <stdexcept>
int riskyFunction(int x) { if (x < 0) throw std::runtime_error("负数!"); return x * 2;}
int main() { std::future<int> future = std::async(std::launch::async, riskyFunction, -5); try { int result = future.get(); std::cout << "结果: " << result << std::endl; } catch (const std::exception& e) { std::cout << "异常: " << e.what() << std::endl; } return 0;}2. std::future和std::promise的高级用法
std::promise是一种手动管理异步结果的工具。您可以在一个线程中设置值或异常,并通过另一个线程中的std::future获取它。这对于实现自定义异步模式非常有用,例如在线程之间传递数据。
示例3:使用std::promise传递数据
#include <iostream>#include <future>#include <thread>
void producer(std::promise<std::string> prom) { std::this_thread::sleep_for(std::chrono::seconds(1)); prom.set_value("数据已就绪!");}
int main() { std::promise<std::string> promise; std::future<s