【C++】异步任务结果传递:promise、future 与 packaged_task
前面介绍了condition_variable解决的是“线程没有任务时如何等待有任务时如何被唤醒”的问题。接下来还有一个很常见的问题子线程执行了一个任务以后任务的返回值怎么交给主线程例如int Add(int a, int b) { return a b; }如果直接创建线程std::thread t(Add, 10, 20);线程当然可以执行Add()但是返回值30怎么拿回来普通std::thread本身不会直接帮我们保存函数返回值。C 提供了std::promise std::future std::packaged_task来解决线程之间的结果传递问题。一、future 可以理解成“未来才能拿到的结果”先从future开始理解。future这个单词本身就是未来所以std::futureint可以理解为现在结果可能还没有计算完成但是未来某个时刻可以通过这个对象拿到一个int。例如std::futureint future;此时future并不直接保存结果它更像是一张“取结果的凭证”。真正获取结果时int result future.get();如果结果已经准备好了get()直接返回。如果结果还没有准备好future.get() ↓ 当前线程等待 ↓ 其他线程完成计算 ↓ 结果准备完成 ↓ get返回结果所以future经常用于主线程提交任务 ↓ 子线程执行任务 ↓ 主线程以后通过future拿结果不过future自己并不能生产结果它需要和std::promise或者std::packaged_task配合使用。二、promise future一个线程设置结果另一个线程获取promise可以理解成我承诺以后会提供一个结果。例如std::promiseint promise;表示未来会产生一个int类型的结果。通过std::futureint future promise.get_future();可以拿到与这个promise对应的future。二者之间的关系可以理解成promise 负责写入结果 ↓ 共享状态 ↑ future 负责读取结果完整示例#include future #include iostream #include thread void Calculate(std::promiseint promise) { int result 10 20; // 将结果设置到共享状态中 promise.set_value(result); } int main() { std::promiseint promise; std::futureint future promise.get_future(); std::thread worker(Calculate, std::move(promise)); // 等待子线程设置结果 int result future.get(); std::cout result result \n; worker.join(); return 0; }输出result 30整个流程是主线程创建promise ↓ 通过get_future得到future ↓ promise交给子线程 ↓ 子线程计算 ↓ promise.set_value(30) ↓ future收到结果 ↓ future.get()返回30这里有一个容易注意到的地方std::thread worker(Calculate, std::move(promise));为什么需要std::move(promise)因为std::promise不能被普通复制。也就是说下面通常不行std::promiseint p1; std::promiseint p2 p1;它只能移动std::promiseint p2 std::move(p1);因为一个promise对应一个共享状态如果随便复制多个promise到底谁负责设置结果就会变得混乱。set_value 是干什么的子线程执行promise.set_value(result);表示结果已经准备完成可以通知 future 了。如果主线程此时正执行future.get();那么它会被唤醒并取得结果。future.get() 只能调用一次例如int result1 future.get(); int result2 future.get();第二次通常会出现错误。因为get()会把共享状态中的结果取走。所以future.get()更像是“领取结果”而不是反复读取变量。如果需要多个地方共享同一个异步结果可以使用std::shared_future不过普通线程池任务返回值大多数情况下std::future已经够用了。三、异常也可以通过 promise 传递异步任务不一定成功。例如int Divide(int a, int b) { if (b 0) { throw std::runtime_error(除数不能为0); } return a / b; }子线程如果直接抛出异常主线程不方便直接得到这个异常。promise可以把异常也保存到共享状态中void Calculate(std::promiseint promise) { try { int result 10 / 0; promise.set_value(result); } catch (...) { promise.set_exception(std::current_exception()); } }主线程try { int result future.get(); } catch (const std::exception e) { std::cout e.what() \n; }完整逻辑子线程正常完成 ↓ promise.set_value() ↓ future.get()得到结果 子线程发生异常 ↓ promise.set_exception() ↓ future.get()重新抛出异常也就是说future不仅可以传递正常返回值也可以把子线程中的异常传递回调用线程。这对于线程池非常重要因为任务执行失败后主线程也需要知道失败原因。四、packaged_task自动把函数返回值放进 future如果每次都手动写std::promiseint promise; std::futureint future promise.get_future();然后在线程函数中promise.set_value(result);会显得比较麻烦。于是 C 提供了std::packaged_task它可以直接包装一个可调用对象并自动把返回值保存到future中。例如int Add(int a, int b) { return a b; }使用packaged_taskstd::packaged_taskint(int, int) task(Add);这里int(int, int)表示这个任务接收两个int参数 返回一个int然后获取结果std::futureint future task.get_future();最后把任务交给线程std::thread worker(std::move(task), 10, 20);完整代码#include future #include iostream #include thread int Add(int a, int b) { return a b; } int main() { std::packaged_taskint(int, int) task(Add); std::futureint future task.get_future(); std::thread worker(std::move(task), 10, 20); int result future.get(); std::cout result result \n; worker.join(); return 0; }输出result 30这里不需要自己写promise.set_value();packaged_task会自动完成执行Add(10, 20) ↓ 得到30 ↓ 把30保存到共享状态 ↓ future.get()得到30所以可以把packaged_task理解成一个能够自动保存函数执行结果的任务包装器。它非常适合线程池。线程池提交任务时通常会把任意函数包装成std::packaged_taskreturn_type()然后把future返回给调用者。例如auto task std::make_sharedstd::packaged_taskint()([]() { return 10 20; }); std::futureint future task-get_future();真正执行任务时(*task)();调用者以后int result future.get();就可以拿到任务结果。这其实就是很多线程池submit()函数的核心思路。五、promise、future、packaged_task 应该怎么理解三者关系可以简单总结为类型主要作用std::promise手动设置结果或异常std::future获取未来产生的结果std::packaged_task包装函数并自动保存返回值promise future更适合手动控制结果产生过程std::promiseint promise; std::futureint future promise.get_future();生产者线程promise.set_value(100);消费者线程int value future.get();而packaged_task future更适合“执行一个函数然后拿到返回值”std::packaged_taskint() task([]() { return 100; }); std::futureint future task.get_future(); task(); int result future.get();在线程池中通常更常见的是用户提交函数 ↓ packaged_task包装函数 ↓ future返回给用户 ↓ task放入任务队列 ↓ 工作线程取出task ↓ 执行task ↓ 返回值自动进入future ↓ 用户future.get()取得结果这也是为什么线程池代码中经常能看到std::future和std::packaged_task一起出现。这一篇最需要掌握的是future负责拿结果 promise负责手动设置结果 promise和future通过共享状态传递数据 future.get()在结果没准备好时会等待 promise可以通过set_exception传递异常 packaged_task可以自动保存函数返回值 线程池通常使用packaged_task包装任务 再把future返回给任务提交者。0voice · GitHub

相关新闻

智能问数POC验证方法论:八个必测场景,告别“demo好看上线翻车“

智能问数POC验证方法论:八个必测场景,告别“demo好看上线翻车“

摘要:传统智能问数/ChatBI的POC做法——准备50个"XX指标是多少"类问题统计准确率——已完全失效。本文提出面向新一代智能问数的POC验证方法论,包括八个必测场景(复杂归因、多轮追问、完整闭环、追问解释、纠错重测、多类型分析、数…

2026/8/11 6:27:09 阅读更多 →
线缆盘绕的电感效应:从原理到实践的风险评估与解决方案

线缆盘绕的电感效应:从原理到实践的风险评估与解决方案

这次我们来看一个在UPS电源、数据中心和工业布线中经常被讨论的实用问题:电源线或信号线盘绕成螺旋状,是否会产生电感效应,以及对设备运行是否存在潜在影响?这个问题看似简单,却直接关系到电气系统的稳定性、设备寿命和…

2026/8/11 6:27:09 阅读更多 →
维护开源项目时,怎样处理卡顿与后台任务泄露

维护开源项目时,怎样处理卡顿与后台任务泄露

维护开源项目时,怎样处理卡顿与后台任务泄露 开源项目的卡顿反馈通常来自不同环境:有人在 CI 里挂住,有人在桌面端看到命令不退出。把这些报告直接归因于“协程泄露”并不可靠。维护者需要的是能让贡献者补齐证据的排查路径,而不是…

2026/8/11 6:26:09 阅读更多 →

最新新闻

高效文件命名与管理系统设计指南

高效文件命名与管理系统设计指南

1. 项目背景与需求分析最近在整理电脑文件时,发现一个特别有意思的现象:我的桌面上躺着十几个名为"无标题"的文档。这种情况相信很多朋友都遇到过,新建文档时随手保存,想着"待会儿再命名",结果一放…

2026/8/11 7:15:31 阅读更多 →
从 Demo 到生产:7 种 Agent 架构设计模式,帮你跨过落地鸿沟!

从 Demo 到生产:7 种 Agent 架构设计模式,帮你跨过落地鸿沟!

01 先说结论:Agent架构不是越复杂越好 在展开之前,先给三个判断: 架构没有绝对高低,只有适不适合 任务越简单,越应该优先用简单架构;任务越长、越复杂,才需要更多控制机制。 Agent 的核心演进方…

2026/8/11 7:15:31 阅读更多 →
刚性常微分方程组的现代数值解法与工程实践

刚性常微分方程组的现代数值解法与工程实践

1. 刚性常微分方程组的工程背景与数学特性刚性(Stiff)常微分方程组在工程实践中极为常见,特别是在涉及多时间尺度耦合的物理系统中。典型的应用场景包括:化学反应动力学(快速反应与慢速反应并存)电路瞬态分…

2026/8/11 7:15:31 阅读更多 →
SFT微调数据准备攻略:4种爆款格式一次讲透,轻松上手!

SFT微调数据准备攻略:4种爆款格式一次讲透,轻松上手!

准备 SFT 微调数据时,核心并不复杂:给模型一条任务,再准备一个希望它学会的标准答案。例如,想让模型学会把一句生硬的话改得更礼貌,就可以准备这样的训练数据: 用户输入:你这个文件写错了&#…

2026/8/11 7:15:31 阅读更多 →
复杂任务开发:如何撰写高质量Spec(规格说明书)指导AI Agent与技能开发

复杂任务开发:如何撰写高质量Spec(规格说明书)指导AI Agent与技能开发

1. 从“一团乱麻”到“清晰蓝图”:为什么复杂任务的 Spec 至关重要干了这么多年项目,无论是带团队攻坚,还是自己独立啃一个硬骨头,我越来越觉得,决定一个复杂任务最终是“优雅落地”还是“一地鸡毛”的,往往…

2026/8/11 7:15:31 阅读更多 →
从AI工具调用到思维重塑:职场人如何驾驭AI成为能力放大器

从AI工具调用到思维重塑:职场人如何驾驭AI成为能力放大器

1. 从“AI威胁论”到“AI赋能论”:一个行业老兵的观察最近,黄仁勋在毕业季的喊话——“AI不会取代你,但善用AI的人会”——又一次在圈内引发了广泛的讨论。作为一名在科技行业摸爬滚打了十多年的从业者,我目睹了从“大数据”到“云…

2026/8/11 7:14:31 阅读更多 →

日新闻

如何用Video2X实现专业级视频画质提升:AI视频增强完整指南

如何用Video2X实现专业级视频画质提升:AI视频增强完整指南

如何用Video2X实现专业级视频画质提升:AI视频增强完整指南 【免费下载链接】video2x A machine learning-based video super resolution and frame interpolation framework. Est. Hack the Valley II, 2018. 项目地址: https://gitcode.com/GitHub_Trending/vi/v…

2026/8/11 0:00:02 阅读更多 →
前后端分离项目中控制台与接口工具数据差异排查指南

前后端分离项目中控制台与接口工具数据差异排查指南

1. 问题现象解析:控制台与Apifox的数据差异 最近在调试一个前后端分离项目时,遇到了一个典型问题:后端服务在本地开发环境控制台能正常输出查询数据,但通过Apifox测试时却返回空结果。这种"控制台有数据,接口工具…

2026/8/11 0:00:03 阅读更多 →
AI编程实战:从Claude Code踩坑到游戏开发入门

AI编程实战:从Claude Code踩坑到游戏开发入门

1. 从“AI能帮我做游戏”到“AI让我重新学编程”最近身边不少朋友,尤其是一些非技术背景、但对游戏开发有浓厚兴趣的朋友,都在问我同一个问题:“听说现在用Claude Code这种AI编程工具,小白也能做游戏了,是真的吗&#…

2026/8/11 0:00:03 阅读更多 →

周新闻

5分钟告别提取码焦虑:baidupankey如何智能破解百度网盘资源锁

5分钟告别提取码焦虑:baidupankey如何智能破解百度网盘资源锁

5分钟告别提取码焦虑:baidupankey如何智能破解百度网盘资源锁 【免费下载链接】baidupankey 在线查询网盘提取码(维护中 rm repo) 项目地址: https://gitcode.com/gh_mirrors/ba/baidupankey 你是否曾经在深夜寻找一份重要资料&#x…

2026/8/11 1:08:05 阅读更多 →
如何快速生成中国车牌图片:Python开源工具完整指南

如何快速生成中国车牌图片:Python开源工具完整指南

如何快速生成中国车牌图片:Python开源工具完整指南 【免费下载链接】chinese_license_plate_generator 中国车牌生成器 项目地址: https://gitcode.com/gh_mirrors/ch/chinese_license_plate_generator 中国车牌生成器是一个基于Python的开源项目&#xff0c…

2026/8/11 1:08:05 阅读更多 →
收藏!小白程序员轻松入门大模型,从Harness工程开始实践

收藏!小白程序员轻松入门大模型,从Harness工程开始实践

文章强调学习大模型不应只关注模型本身,而应重视模型外的系统搭建,即Harness。提出AgentModelHarness的实用公式,详细介绍Harness的四个层次:持久化层、执行层、控制层和观察与验证层。文章还探讨了上下文工程、工具设计、AGENTS.…

2026/8/11 1:08:05 阅读更多 →

月新闻

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南 【免费下载链接】BaiduNetdiskPlugin-macOS For macOS.百度网盘 破解SVIP、下载速度限制~ 项目地址: https://gitcode.com/gh_mirrors/ba/BaiduNetdiskPlugin-macOS 还在为百度网盘macOS版的龟速下…

2026/8/10 17:07:33 阅读更多 →
终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换

终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换

终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换 【免费下载链接】ncmdump 项目地址: https://gitcode.com/gh_mirrors/ncmd/ncmdump 还在为网易云音乐下载的NCM格式文件无法在其他播放器播放而烦恼吗?ncmdump解密工具帮你轻松解决这个困…

2026/8/11 1:08:06 阅读更多 →
HarmonyOS 应用开发《掌上英语》第81篇: 智能体卡片:为英语学习 App 打造桌面级学习助手

HarmonyOS 应用开发《掌上英语》第81篇: 智能体卡片:为英语学习 App 打造桌面级学习助手

AgentCard 智能体卡片:为英语学习 App 打造桌面级学习助手适用平台:HarmonyOS 7.0 (API 26 Beta)一、引言 HarmonyOS 7.0(API 26 Beta)新增了 AgentCard 智能体卡片能力,这是继 HMAF(鸿蒙智能体框架&#x…

2026/8/10 17:07:33 阅读更多 →