为何std::async同时指定async|deferred时deferred未延迟执行?
问题与解答
测试代码
#include <future> #include <string> #include <iostream> #include <chrono> #include <thread> using namespace std::chrono_literals; int main() { int v = 0; auto a1 = std::async( std::launch::async | std::launch::deferred, [&v]() { std::cout << "begin 1" << std::endl; std::cout << "v = " << v << std::endl; std::this_thread::sleep_for(100ms); std::cout << "end 1" << std::endl; }); auto a2 = std::async( std::launch::async | std::launch::deferred, [&v]() { std::cout << "begin 2" << std::endl; std::this_thread::sleep_for(200ms); v = 123; std::cout << "end 2" << std::endl; }); a2.wait(); // 我原本认为a1会在此处才开始执行? // 这样v应该输出123而非0? a1.wait(); return 0; }
问题描述
使用std::launch::async | std::launch::deferred组合策略调用std::async时,观察到a1与a2并发执行,且v输出为0;但仅使用deferred策略时,程序表现符合预期(先执行a2修改v为123,再执行a1输出123)。想明确:为何会出现这种差异?async策略是否会影响deferred的行为?
解答
这是C++标准对std::async组合策略的规定直接导致的:
- 当同时指定
std::launch::async和std::launch::deferred时,标准库实现拥有完全选择权——它可以选择立刻在新线程中执行任务(遵循async策略),也可以选择延迟到调用wait()或get()时再执行(遵循deferred策略)。标准没有强制要求优先使用deferred,实现会根据系统资源、线程池负载等情况自行决策。 - 你的测试中,标准库选择了对
a1和a2都采用async策略,因此两个任务在创建后就立刻在后台线程并发执行了。a1执行输出v时,a2还在200ms的sleep过程中,尚未修改v,所以输出0。 - 当仅指定
std::launch::deferred时,任务会严格遵循延迟执行规则:只有调用wait()或get()时,任务才会在当前调用线程(主线程)中同步执行。因此你先调用a2.wait(),a2执行完毕修改v为123,之后a1.wait()触发a1执行,此时v已经是123,符合预期。
总结:如果必须保证任务延迟执行,只能单独指定std::launch::deferred,不能与async策略组合——组合策略下的行为是不确定的,完全由标准库实现决定。
内容的提问来源于stack exchange,提问作者lk.c
相关产品推荐
相关产品推荐

