0

0

C++ std::async 异步执行策略是什么?(如何控制任务是在新线程运行)

尼克

尼克

发布时间:2026-02-18 13:11:02

|

730人浏览过

|

来源于php中文网

原创

std::async 默认使用 std::launch::deferred | std::launch::async 组合策略,具体由实现决定,常见编译器倾向延迟执行(deferred),即调用 get() 或 wait() 时才在当前线程同步运行,不创建新线程。

c++ std::async 异步执行策略是什么?(如何控制任务是在新线程运行)

std::async 默认用什么策略启动任务?

默认不是总开新线程——它用的是 std::launch::deferred | std::launch::async 组合策略,具体选哪个由实现决定,但常见编译器(如 GCC、MSVC)在未显式指定时倾向延迟执行(deferred),也就是调用 get()wait() 时才同步运行,根本不动线程。

这意味着你写:

auto fut = std::async([]{ return 42; });

很可能啥线程都没创建,直到你调用 fut.get() 才在当前线程执行。这不是 bug,是标准允许的行为。

  • 想强制新开线程?必须显式传 std::launch::async
  • 想确保延迟执行?传 std::launch::deferred
  • 混用两个 flag(如 std::launch::async | std::launch::deferred)没意义,标准禁止

怎么确保任务一定在新线程里跑?

只有一种可靠方式:显式指定 std::launch::async 策略,并且别依赖默认行为。

立即学习C++免费学习笔记(深入)”;

LOGO.com
LOGO.com

在线生成Logo,100%免费

下载
auto fut = std::async(std::launch::async, []{
    std::this_thread::sleep_for(std::chrono::seconds(1));
    return 42;
});

这时系统必须立即派生新线程(或从线程池取一个)来执行 lambda。验证方法很简单:在 lambda 里打日志 + 查看线程 ID,或者用调试器观察线程数变化。

  • 别省略第一个参数——漏掉就退回默认策略,行为不可控
  • 如果任务很快,新线程开销可能比执行本身还大,注意权衡
  • Windows 上 MSVC 的 std::async 实现曾有线程复用逻辑,但只要用了 async 标志,语义上仍是“异步启动”,不保证复用哪个线程

std::launch::deferred 有什么实际用途?

它本质是“懒执行”包装器,适合做条件性、按需触发的计算,比如缓存未命中时才真正算,且不希望提前占资源。

典型场景:配置解析、重试逻辑封装、避免构造开销。

  • 返回 std::future 后,不调 get()/wait() 就不会执行函数体
  • deferred 任务永远在调用 get() 的线程上执行(即同步、无并发),所以不用考虑线程安全
  • 不能和 async 混用;也不能用于需要并行执行多个任务的场景
  • 错误现象:以为开了后台线程,结果 get() 一调整个主线程卡住——其实是 deferred 在同步执行

为什么有时候 std::async 不开线程,甚至卡死?

最常见原因有两个:一是没指定 std::launch::async,走了默认策略(可能是 deferred);二是 std::future 对象被销毁前没调 get()wait(),而它内部持有一个阻塞析构锁(C++11 规定:若 future 关联 deferred 任务,析构时会强制执行;若关联 async 任务,析构会阻塞等待完成)。

  • 后果:局部 std::future 变量离开作用域时卡住当前线程,尤其在循环或短生命周期函数里容易中招
  • 解法:明确策略 + 显式管理生命周期,例如用 std::shared_future 避免重复析构,或用 std::future::valid() 判断再决定是否 get()
  • GCC libstdc++ 曾在某些版本对 deferred future 析构做同步执行,导致意外阻塞,升级标准库可缓解

线程调度不是黑盒,std::async 的策略开关就是你唯一能握在手里的控制柄。漏掉 std::launch::async,等于把线程创建权交给了编译器实现——而它通常选择最省事的方式,不是你想要的方式。

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
lambda表达式
lambda表达式

Lambda表达式是一种匿名函数的简洁表示方式,它可以在需要函数作为参数的地方使用,并提供了一种更简洁、更灵活的编码方式,其语法为“lambda 参数列表: 表达式”,参数列表是函数的参数,可以包含一个或多个参数,用逗号分隔,表达式是函数的执行体,用于定义函数的具体操作。本专题为大家提供lambda表达式相关的文章、下载、课程内容,供大家免费下载体验。

212

2023.09.15

python lambda函数
python lambda函数

本专题整合了python lambda函数用法详解,阅读专题下面的文章了解更多详细内容。

192

2025.11.08

Python lambda详解
Python lambda详解

本专题整合了Python lambda函数相关教程,阅读下面的文章了解更多详细内容。

58

2026.01.05

线程和进程的区别
线程和进程的区别

线程和进程的区别:线程是进程的一部分,用于实现并发和并行操作,而线程共享进程的资源,通信更方便快捷,切换开销较小。本专题为大家提供线程和进程区别相关的各种文章、以及下载和课程。

675

2023.08.10

线程和进程的区别
线程和进程的区别

线程和进程的区别:线程是进程的一部分,用于实现并发和并行操作,而线程共享进程的资源,通信更方便快捷,切换开销较小。本专题为大家提供线程和进程区别相关的各种文章、以及下载和课程。

675

2023.08.10

windows查看端口占用情况
windows查看端口占用情况

Windows端口可以认为是计算机与外界通讯交流的出入口。逻辑意义上的端口一般是指TCP/IP协议中的端口,端口号的范围从0到65535,比如用于浏览网页服务的80端口,用于FTP服务的21端口等等。怎么查看windows端口占用情况呢?php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

1159

2023.07.26

查看端口占用情况windows
查看端口占用情况windows

端口占用是指与端口关联的软件占用端口而使得其他应用程序无法使用这些端口,端口占用问题是计算机系统编程领域的一个常见问题,端口占用的根本原因可能是操作系统的一些错误,服务器也可能会出现端口占用问题。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

1150

2023.07.27

windows照片无法显示
windows照片无法显示

当我们尝试打开一张图片时,可能会出现一个错误提示,提示说"Windows照片查看器无法显示此图片,因为计算机上的可用内存不足",本专题为大家提供windows照片无法显示相关的文章,帮助大家解决该问题。

820

2023.08.01

pixiv网页版官网登录与阅读指南_pixiv官网直达入口与在线访问方法
pixiv网页版官网登录与阅读指南_pixiv官网直达入口与在线访问方法

本专题系统整理pixiv网页版官网入口及登录访问方式,涵盖官网登录页面直达路径、在线阅读入口及快速进入方法说明,帮助用户高效找到pixiv官方网站,实现便捷、安全的网页端浏览与账号登录体验。

561

2026.02.13

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
C# 教程
C# 教程

共94课时 | 9.6万人学习

C 教程
C 教程

共75课时 | 4.8万人学习

C++教程
C++教程

共115课时 | 18.2万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号