当前位置: 首页 > ds >正文

【C++】C++异步编程四剑客:future、async、promise和packaged_task详解

C++异步编程四剑客:future、async、promise和packaged_task详解

1. 引言

1.1 异步编程的重要性

在现代C++编程中,异步操作是提高程序性能和响应能力的关键技术。它允许程序在等待耗时操作(如I/O、网络请求或复杂计算)完成时继续执行其他任务,从而充分利用系统资源。

1.2 C++中的异步工具

C++11引入了强大的异步编程支持,主要包括四个核心组件:

  • std::future/std::shared_future:异步结果获取机制
  • std::async:简单的异步任务启动器
  • std::promise:异步结果提供者
  • std::packaged_task:可调用对象的包装器

2. std::future:异步结果的桥梁

2.1 基本概念

std::future是一个模板类,它提供了一种访问异步操作结果的机制。一个future对象通常与某个异步操作相关联,并可以在未来某个时刻获取该操作的结果。

2.2 主要功能

  • get():获取异步操作的结果(如果结果未就绪,会阻塞当前线程)
  • wait():等待异步操作完成
  • wait_for()/wait_until():带超时的等待

2.3 使用示例

#include <iostream>
#include <future>
#include <thread>int compute() {std::this_thread::sleep_for(std::chrono::seconds(2));return 42;
}int main() {std::future<int> result = std::async(std::launch::async, compute);std::cout << "Waiting for result..." << std::endl;std::cout << "Result: " << result.get() << std::endl;return 0;
}

3. std::async:简单的异步任务启动器

3.1 基本用法

std::async是启动异步任务的最简单方式,它返回一个std::future对象,通过该对象可以获取异步任务的结果。

3.2 启动策略

  • std::launch::async:强制在新线程中执行
  • std::launch::deferred:延迟执行,直到调用future.get()future.wait()
  • 默认策略:由实现决定

3.3 注意事项

  • 返回值std::future析构时会隐式等待
  • 不适合需要精细控制线程的场景

3.4 示例代码

auto future1 = std::async(std::launch::async, []{// 耗时计算return calculateSomething();
});auto future2 = std::async(std::launch::deferred, []{// 这个任务不会立即执行return calculateSomethingElse();
});// 只有调用get()时才会执行future2的任务
auto result = future1.get() + future2.get();

4. std::promise:手动设置异步结果

4.1 核心概念

std::promise允许显式地设置一个值或异常,这个值可以通过关联的std::future对象获取。

4.2 典型使用场景

  • 需要手动控制结果设置的时机
  • 跨线程回调
  • 复杂异步流程控制

4.3 基本用法

#include <iostream>
#include <future>
#include <thread>void compute(std::promise<int> prom) {try {int result = 42; // 模拟计算prom.set_value(result);} catch(...) {prom.set_exception(std::current_exception());}
}int main() {std::promise<int> prom;std::future<int> fut = prom.get_future();std::thread t(compute, std::move(prom));t.detach();std::cout << "Result: " << fut.get() << std::endl;return 0;
}

5. std::packaged_task:可调用对象的包装器

5.1 基本概念

std::packaged_task包装一个可调用对象(函数、lambda表达式、函数对象等),并允许异步获取该调用的结果。

5.2 主要特点

  • 将任务与结果获取分离
  • 可以像普通函数对象一样被调用
  • 适合需要将任务传递给线程池的场景

5.3 使用示例

#include <iostream>
#include <future>
#include <thread>
#include <deque>std::deque<std::packaged_task<int()>> task_queue;void worker_thread() {while (!task_queue.empty()) {auto task = std::move(task_queue.front());task_queue.pop_front();task(); // 执行任务}
}int main() {std::packaged_task<int()> task([]{return 42;});std::future<int> result = task.get_future();task_queue.push_back(std::move(task));std::thread t(worker_thread);t.join();std::cout << "Result: " << result.get() << std::endl;return 0;
}

6. 四者的比较与选择指南

6.1 功能对比

工具适用场景线程管理灵活性
std::async简单异步任务自动
std::promise需要手动设置结果的复杂场景手动
std::packaged_task需要传递任务对象的场景手动

6.2 选择建议

  1. 优先考虑std::async:适用于简单的异步任务
  2. 需要精细控制时使用std::promise
  3. 需要将任务对象传递给线程池时使用std::packaged_task

7. 高级主题与最佳实践

7.1 异常处理

  • 使用promise.set_exception()传递异常
  • future.get()时捕获异常

7.2 超时控制

auto status = future.wait_for(std::chrono::seconds(1));
if (status == std::future_status::ready) {// 任务已完成
} else {// 超时处理
}

7.3 共享结果

使用std::shared_future实现多线程共享异步结果:

std::promise<int> prom;
std::shared_future<int> shared_fut = prom.get_future().share();// 多个线程可以同时访问shared_fut

8. 总结

C++的异步编程工具提供了不同层次的抽象,从简单的std::async到更灵活的std::promisestd::packaged_task,开发者可以根据具体需求选择合适的工具。理解这些工具的特性和适用场景,能够帮助我们编写出更高效、更健壮的并发程序。

http://www.xdnf.cn/news/8766.html

相关文章:

  • DeepSeek实战--MCP Client Stdio模式
  • DataFrame 和 Dataset的对比理解
  • 常见嵌入式软件架构
  • Spring Boot微服务架构(三):Spring Initializr创建CRM项目
  • 基于CodeBuddy实现本地网速的实时浏览小工具
  • 网络安全从零开始(二):细分技术方向深度解析
  • GM DC Monitor 系统监控对象SNMP配置指南
  • Linux中的前台(同步)运行 或 后台(异步)运行
  • java 代码查重(四)删除java文件中注释的方法后查重实现
  • 鼠标连点器 ,实现鼠标自动点击
  • DVWA通关笔记-靶场安装教程
  • SQL每日一题(5)
  • 阿斯利康医学代表在线测评笔试题库 | 3天备考、能力测评、性格测评历年真题 | 华东同舟求职讲求职
  • 分布式缓存:缓存设计中的 7 大经典问题_缓存失效、缓存穿透、缓存雪崩
  • RV1126+FFMPEG多路码流监控项目大体讲解
  • 【软件测试】第三章·软件测试基本方法(缺陷模式、模型、形式化测试方法)
  • 关键点翻转 数据增强踩坑
  • C++性能相关的部分内容
  • 数据类型与运算符
  • 6.3.1图的广度优先遍历
  • 第一课:医学影像研究的科学思维与问题提出
  • js实现音频的录制
  • Vue 样式不一致问题全面分析与解决方案
  • 专业学习|经济学与管理学常用分析工具详解
  • 【人工智能】微调秘籍:解锁AI大模型的定制化魔法
  • python装饰器的简单理解
  • (2)-玩转Fiddler抓包-再识Fiddler
  • 天地图实景三维数据分享(江苏)
  • 【iOS】内存分区
  • 第2周 PINN核心技术揭秘: 如何用神经网络求解偏微分方程