当前位置: 首页 > 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配合使用时。第一种方式虽然也能工作,但在复杂的异步编程场景中可能不够安全。

相关文章:

  • 【Hive入门】Hive分桶表深度解析:从哈希分桶到Join优化的完整指南
  • Ubuntu编译opencv源码
  • SpringBoot实现的后端开发
  • 【计算机视觉】CV实战项目 -深度解析PaddleSegSharp:基于PaddleSeg的.NET图像分割解决方案
  • 数值数据处理的黄金法则:构建高质量机器学习模型的基石‌
  • per-task affinity 是什么?
  • 思科路由器重分发(静态路由+OSPF动态路由+RIP动态路由)
  • 配置文件的四级分类
  • 在Mybatis中为什么要同时指定扫描mapper接口和 mapper.xml 文件,理论单独扫描 xml 文件就可以啊
  • 数字IC后端实现教程之InnovusICC2添加Tie High/Low cell脚本
  • 4月25日日记(补)
  • 山东大学软件学院项目实训-基于大模型的模拟面试系统-前端美化滚动条问题
  • 桌面端开发技术栈选型:开启高效开发之旅
  • Eigen库编译
  • BT152-ASEMI机器人率器件专用BT152
  • Graphpad Prism10.1.2 中文版科学绘图软件 安装包下载
  • c#简易超市充值卡程序充值消费查余额
  • autodl(linux)环境下载git-lfs等工具及使用
  • 数字技术驱动下教育生态重构:从信息化整合到数字化转型的路径探究
  • 在Windows11中配置Git+SSH环境,本此实践使用Gitee(码云),方法同样适用于其它绝大部分Git服务
  • 停电催生商机,中国品牌 “照亮” 西班牙
  • 两部门预拨4000万元支持山西、广西、陕西做好抗旱救灾工作
  • 揭秘神舟十九号返回舱“软着陆”关键:4台发动机10毫秒内同时点火
  • 移动互联网未成年人模式正式发布
  • 张炜琳已任三明市委常委、宣传部部长
  • 光明日报:回应辅警“转正”呼声,是一门政民互动公开课