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

c++ package_task

int print_sum(int a, int b) {std::cout << a << " + " << b << " = " << (a + b) << std::endl;return a + b;
}int main() {// 创建绑定后的可调用对象auto print_sum_5 = std::bind(print_sum, 5, 6);// 包装为 packaged_task//std::packaged_task<int(int)> task(print_sum_5);auto task = std::make_shared<std::packaged_task<int()>>(print_sum_5);// 获取 futureauto future = task->get_future();// 在新线程中执行// std::thread t(std::move(*task) );std::thread t([task]() {(*task)(); });t.join();// 对于 void 返回类型,future.get() 只是等待完成int c=  future.get();std::cout << c << std::endl;return 0;
}

// 在新线程中执行
std::thread t(std::move(*task) );
std::thread t([task]() {(*task)(); });
这2中写法都可以运行 具体怎么解释 有什么不同
 

这两种线程启动方式都可以工作,但它们有不同的语义和适用场景。我来详细解释它们的区别:

1. std::thread t(std::move(*task));

工作原理:
  • 解引用 shared_ptr 得到 packaged_task 对象

  • 使用 std::move 将对象的所有权转移到新线程

  • 线程构造函数直接调用 packaged_task 的 operator()

特点:
  • 所有权转移packaged_task 被移动到新线程中,原始 task 变为空

  • 一次性使用packaged_task 只能被调用一次,移动后原对象不再可用

  • 不需要lambda:更直接,但灵活性较低

潜在问题:
  • 如果其他代码还想使用这个 task 会出问题(因为已被移动)

  • shared_ptr 的引用计数机制在这里实际上没有被充分利用

2. std::thread t([task]() {(*task)(); });

工作原理:
  • Lambda 以值捕获方式捕获 shared_ptr(增加引用计数)

  • 在新线程中解引用并调用 packaged_task

  • shared_ptr 保证 packaged_task 生命周期

特点:
  • 共享所有权shared_ptr 的引用计数确保对象存活

  • 更安全:即使主线程先结束,packaged_task 仍然有效

  • 更灵活:可以在lambda中添加额外逻辑

  • 符合RAII:更好地利用 shared_ptr 的生命周期管理

优势:
  • 允许多个线程共享访问同一个任务(虽然通常不推荐)

  • 更适合复杂场景或需要额外处理的情况

关键区别对比:

特性std::move(*task) 方式Lambda捕获 shared_ptr 方式
所有权转移所有权共享所有权
生命周期管理依赖线程生命周期由 shared_ptr 引用计数管理
灵活性较低较高(可在lambda中添加逻辑)
线程安全一般更好
典型使用场景简单的一次性任务需要更复杂控制的场景
packaged_task状态移动后原对象无效原 shared_ptr 仍可使用

为什么两种方式都能工作?

在你的特定例子中:

  1. std::bind 已经绑定了所有参数,创建的是无参可调用对象

  2. packaged_task 只需要被调用一次

  3. 主线程会等待(t.join())所以生命周期问题不会显现

推荐选择:

  • 简单场景:使用 std::move(*task) 更简洁

  • 复杂/生产代码:推荐lambda方式,因为:

    • 更安全(明确的生命周期管理)

    • 更灵活(方便添加异常处理等)

    • 更符合现代C++的惯用法

代码示例对比:

// 方式1:移动语义
auto task = std::make_shared<std::packaged_task<int()>>(std::bind(print_sum,5,6));
auto future = task->get_future();
std::thread t1(std::move(*task));  // task现在为空
t1.join();// 方式2:lambda捕获
auto task = std::make_shared<std::packaged_task<int()>>(std::bind(print_sum,5,6));
auto future = task->get_future();
std::thread t2([task]{ (*task)(); });  // task仍有效
t2.join();

在大多数现代C++代码中,第二种方式(lambda捕获)更受推荐,因为它提供了更好的安全性和灵活性,特别是当与shared_ptr配合使用时。第一种方式虽然也能工作,但在复杂的异步编程场景中可能不够安全。

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

相关文章:

  • 10:00面试,10:08就出来了,面试问的问题太。。。
  • AMP混合精度训练 详细解析
  • 2025.04.26-美团春招笔试题-第三题
  • 基于OpenMV+STM32+OLED与YOLOv11+PaddleOCR的嵌入式车牌识别系统开发笔记
  • Unity任务系统笔记
  • 第十六周蓝桥杯2025网络安全赛道
  • 线程池单例模式
  • JSAPI2.4——正则表达式
  • 微信小程序,基于uni-app的轮播图制作,轮播图本地文件图片预览
  • 4.26学习——web刷题
  • 头歌实训之存储过程、函数与触发器
  • leetcode 283和2460
  • 【运维】云端掌控:用Python和Boto3实现AWS资源自动化管理
  • react 报错
  • 路由交换网络专题 | 第八章 | GVRP配置 | 端口安全 | 端口隔离 | Mux-VLAN | Hybrid
  • SinSR模型剪枝实验报告
  • 【LeetCode 热题 100】链表 系列
  • WPF实现数字孪生示例
  • linux socket编程之tcp(实现客户端和服务端消息的发送和接收)
  • 北斗导航 | 基于Transformer+LSTM+激光雷达的接收机自主完好性监测算法研究
  • Ext JS模拟后端数据之SimManager
  • 模型识别能力锤炼及清单
  • 8.学习笔记-Maven进阶(P82-P89)
  • AI数字人:未来职业的重塑(9/10)
  • 【高频考点精讲】第三方库安全审计:如何避免引入带漏洞的npm包
  • springboot入门-service层构造器注入原理
  • 推荐系统FM模型
  • 2025.4.26_STM32_SPI
  • 29、简要描述三层架构开发模式以及三层架构有哪些好处?
  • Vue3中AbortController取消请求的用法详解