1. C++ async 基础与核心机制
C++11引入的std::async是异步编程的重要工具,它封装了线程创建和任务调度的复杂性。理解其底层机制是正确使用的前提。
1.1 async的两种启动策略
std::async提供两种基本启动策略,通过std::launch枚举指定:
cpp复制enum class launch {
async = 1,
deferred = 2,
// 实现可能定义额外策略
};
-
异步启动(std::launch::async):立即在新线程中执行任务,这是真正的异步执行。如果系统资源不足,会抛出std::system_error异常。
-
延迟启动(std::launch::deferred):任务不会立即执行,而是在调用future.get()或future.wait()时,在调用线程中同步执行。这种策略适合那些不急于计算但需要异步接口的任务。
默认情况下(不显式指定策略),async使用std::launch::async | std::launch::deferred,这意味着实现可以选择立即异步执行或延迟执行,这可能导致不确定的行为。
1.2 返回值与共享状态
async返回std::future对象,它代表异步操作的"未来"结果。这个future与一个共享状态关联:
cpp复制auto future = std::async([](){ return 42; });
// 共享状态包含:任务函数、参数、执行结果/异常
共享状态的生命周期管理是async行为的关键。当最后一个引用它的future被销毁时,如果任务还未完成,会阻塞等待任务完成(除非future被移动或分离)。
1.3 任务调度与线程模型
async的线程行为取决于实现:
- 可能每次都创建新线程
- 可能使用线程池复用线程
- 延迟策略下根本不创建线程
这种实现自由度带来了可移植性挑战。例如,MSVC和GCC在处理默认策略时可能有不同行为。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 使用async的注意事项与最佳实践
2.1 策略选择与确定性行为
显式指定策略是避免不确定性的关键:
cpp复制// 明确需要异步执行时
auto fut1
