当前位置: 首页 > 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服务
  • 美加征“对等关税”后,调研显示近半外贸企业将减少对美业务
  • 商超展销延长、专区专柜亮相……上海“外贸拓内销”商品与市民见面
  • 2025上海车展的三个关键词:辅助驾驶、性价比,AI生态
  • 广州一人均500元的日料店回收食材给下一桌?市场监管部门介入调查
  • 阿曼外交大臣:伊美下一轮谈判暂定5月3日举行
  • 三部门提出17条举措,全力促进高校毕业生等青年就业创业