C++多线程编程(3):接收线程处理函数的返回值

文章首发于我的个人博客:欢迎大佬们来逛逛

文章目录

  • 处理带返回值的函数
    • async
    • packaged_task
    • promise

处理带返回值的函数

有三种方法:

  • async
  • packaged_task
  • promise

async

第一种方法是使用 async 函数。

步骤:

  1. 使用 async 创建线程处理函数
  2. 使用 .get() 获取返回值。

async函数具有两个属性

  • launch::async(默认):表示创建线程处理函数并且立刻执行
  • launch::defered:延期,当使用wait或者get的时候才会执行线程处理函数

async函数的返回值:std::future 类型,通过调用其 get 方法获取返回值

下面分别演示了普通函数类的成员函数以及 defered 的作用:

int value1(int num) {return num; 
}//类对象
class Foo {
public:Foo() {}int getValue(int num) {std::chrono::milliseconds duration(2000);std::this_thread::sleep_for(duration);return num * 2;}
};void testAsync() {//直接执行,默认是launch::asyncstd::future<int> res1 = std::async(value1, 100);std::cout << res1.get() << '\n';Foo m{};//类成员函数std::future<int> res2 = std::async(&Foo::getValue, &m, 200);std::cout << res2.get() << '\n';//不会立刻执行auto res3 = std::async(std::launch::deferred, &Foo::getValue, m, 400);//调用get,执行线程std::cout << res3.get() << '\n';
}

在这里插入图片描述


packaged_task

第二种方法是使用 packaged_task 方法

步骤:

  1. 使用 packaged_task 来包装线程处理函数
  2. 然后将这个包装好的函数加入到线程 thread 中,并且执行线程处理函数
  3. 最后使用这个 packaged_task 调用 get_future 来获取 future,然后调用 get 获取值。

package_task 函数包装语法:

//包装普通函数
std::packaged_task<返回类型(形参列表)> pack1(函数名称);//包装类的成员函数
std::packaged_task<返回类型(形参列表)> pack2(bind(函数地址,成员变量地址,placeholders占位符))//包装lambda表达式
std::packaged_task<int(int)> pack3([](形参列表){xxxxreturn xxx;
});

可以看到对于类的成员函数是相对比较复杂的。

void testPackaged_task() {//1. 普通函数的包装std::packaged_task<int(int)> pack1(value1);std::thread t1(std::ref(pack1),100);  //转换为&&t1.join();std::cout << pack1.get_future().get() << '\n';//2. 类中成员函数的包装Foo m{};std::packaged_task<int(int)> pack2(std::bind(&Foo::getValue, &m, std::placeholders::_1));std::thread t2(std::ref(pack2), 200);t2.join();std::cout << pack2.get_future().get() << '\n';//3. lambda表达式std::packaged_task<int(int)> pack3([](int num) {std::cout << "id: " << std::this_thread::get_id() << '\n';return num * 2;});std::thread t3(std::ref(pack3),300);t3.join();std::cout << pack3.get_future().get() << '\n';
}

在这里插入图片描述


promise

第三种方法是使用 promise 类型

步骤:

  1. 传递 promise 类型的变量到线程处理函数中。
  2. 我们正常执行线程处理函数即可,无需使用return语句,在操作完成后把需要的值 set_value 设置为promise 的值。
  3. 然后使用 thread 创建并且执行线程处理函数。
  4. 然后我们就可以在外部使用 .get_future 获取 future对象, 继而 .get 获取值。

这种方法的特点:

  • 无需显示设置 return 语句
  • 需要往线程处理函数添加一个额外的 promise 类型的参数。

例如这个是我们的线程处理函数,我们需要返回 num *3, 但是现在我们添加一个promise 类型的参数(注意是引用),然后直接 set_value 即可,然后再外部就可以直接访问这个值了。

void testThread(std::promise<int>& pms, int num) {std::cout << get_id() << '\n';pms.set_value(num * 3);
}
  • 返回线程处理函数的值:
std::promise<int> pms;
std::thread t1(testThread, std::ref(pms), 100);
t1.join();
auto num = pms.get_future().get();
std::cout << num << '\n';

这种方法也可以传递线程的值到另一个线程处理函数中:

有一个 testGetValueThread 线程函数,我们需要把刚才获取的 num*3 的值再传递进去,则可以在这个线程函数内调用 .get_future().get() 来传递参数。

下面是两种方法,这里使用了函数重载作为线程处理函数,需要使用static_cast来避免重载歧义。

通过static_cast消除重载函数的歧义

void testGetValueThread(std::promise<int>& pms) {std::cout << "获取值: " << pms.get_future().get() << '\n';
}
void testGetValueThread(int num) {std::cout << "获取值: " << num << '\n';
}...std::promise<int> pms2;pms2.set_value(99);//值传递到其他线程中//通过static_cast消除重载函数的歧义std::thread t2(static_cast<void(*)(std::promise<int>&)>(testGetValueThread), std::ref(pms2));t2.join();std::thread t3(static_cast<void(*)(int)>(testGetValueThread), num);t3.join();

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/150217.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

16. @PostConstruct注解和开关原理(验证码开关、IP开关)

1►PostConstruct注解 PostConstruct是java自带的注解&#xff0c;会在java项目启动的时候先执行下面的方法 2►开关原理&#xff08;验证码开关&#xff09; 我们的项目具有验证码功能&#xff0c;旧版不支持关闭&#xff0c;新版已经支持关闭了。 我们打开页面“参数管…

Python Web APP在宝塔发布

本地测试运行&#xff1a;uvicorn main:app --host 127.0.0.1 --port 8082 --reload 宝塔发布&#xff1a; 运行配置——>启动模式&#xff1a;worker_class uvicorn.workers.UvicornWorker

【STL】:反向迭代器

朋友们、伙计们&#xff0c;我们又见面了&#xff0c;本期来给大家解读一下有关反向迭代器的模拟实现&#xff0c;如果看完之后对你有一定的启发&#xff0c;那么请留下你的三连&#xff0c;祝大家心想事成&#xff01; C 语 言 专 栏&#xff1a;C语言&#xff1a;从入门到精通…

rabbitMQ的direct模式的生产者与消费者使用案例

消费者C1的RoutingKey 规则按照info warn 两种RoutingKey匹配 绑定队列console package com.esint.rabbitmq.work03;import com.esint.rabbitmq.RabbitMQUtils; import com.rabbitmq.client.Channel; import com.rabbitmq.client.DeliverCallback;/*** 消费者01的消息接受*/ p…

如何使用MybatisPlus进行数据分页显示

如何使用MybatisPlus进行数据的分页呢&#xff1f; 使用Mybatis Plus提供的分页插件来简化开发&#xff0c;在MybatisPlusInterceptor的拦截器中添加自动分页的PaginationInnerInterceptor拦截器&#xff0c;当前配置需要交给spring的bean管理&#xff0c;类上添加注解Configu…

目标检测 Faster RCNN全面解读复现

Faster RCNN 解读 经过R-CNN和Fast RCNN的积淀&#xff0c;Ross B. Girshick在2016年提出了新的Faster RCNN&#xff0c;在结构上&#xff0c;Faster RCNN已经将特征抽取(feature extraction)&#xff0c;proposal提取&#xff0c;bounding box regression(rect refine)&…

php聊天室通讯系统常用的接口对接函数 curl、file_get_contents()、WebSocket、消息队列

方法有&#xff1a; 1、HTTP请求&#xff0c;可以通过PHP的curl库或者file_get_contents()函数发送HTTP请求来与聊天室接口进行通信&#xff1b; 2、WebSocket协议&#xff0c;可以使用PHP的WebSocket库或者第三方库来与聊天室接口进行对接&#xff1b; 3、使用这些SDK或者包装…

GIT提交代码

1、从远端克隆master分支 git clone -b master ssh://git*** 2、创建开发分支 git checkout -b 209192_dev 3、在对应分支下更新代码 -f为强制更新&#xff0c;会覆盖本地 git pull -f origin 209192_dev:209192_dev git pull -f origin sit:sit git pull -f origin uat:uat 4、…

Nginx快速入门教程,域名转发、负载均衡

1.Nginx简介 Nginx是⽬前最流⾏的Web服务器&#xff0c; 最开始是由⼀个叫做igor的俄罗斯的程序员开发的&#xff0c; 2019年3⽉11⽇被美国的F5公司以6.7亿美元的价格收购&#xff0c; 现在Nginx是F5公司旗下的⼀款产品了。 2.Nginx的版本 Nginx开源版本主要分为两种&#x…

21、嵌套路由实战操作

1、创建内嵌子路由&#xff0c;你需要添加一个vue文件&#xff0c;同时添加一个与该文件同名的目录用来存放子视图组件。 2、在父组件&#xff08;.vue&#xff09;内增加用于显示子视图内容 新建文件 pages\index_id.vue 生成的对应路由 {path: "/",component: _…

电子病历编辑器源码(Springboot+原生HTML)

一、系统简介 本系统主要面向医院医生、护士&#xff0c;提供对住院病人的电子病历书写、保存、修改、打印等功能。本系统基于云端SaaS服务方式&#xff0c;通过浏览器方式访问和使用系统功能&#xff0c;提供电子病历在线制作、管理和使用的一体化电子病历解决方案&#xff0c…

产品经理不得不知道的电商API接口对接流程梳理

接口对接流程梳理 产品经理 知晓自己负责系统做什么&#xff0c;外接三方系统做什么。 系统对接产品经理实操步骤&#xff1a; ①与公司业务人员沟通&#xff0c;与系统对接方产品/技术描述业务场景&#xff0c;沟通发放接口文档材料 ②拿到材料之后电商API接口过多请对方…

武汉站--ChatGPT/GPT4科研技术应用与AI绘图及论文高效写作

2023年随着OpenAI开发者大会的召开&#xff0c;最重磅更新当属GPTs&#xff0c;多模态API&#xff0c;未来自定义专属的GPT。微软创始人比尔盖茨称ChatGPT的出现有着重大历史意义&#xff0c;不亚于互联网和个人电脑的问世。360创始人周鸿祎认为未来各行各业如果不能搭上这班车…

麒麟KYLINOS2303系统上禁用新功能介绍页面

原文链接&#xff1a;麒麟KYLINOS2303系统上禁用新功能介绍页面 hello&#xff0c;大家好啊&#xff0c;今天给大家带来一篇在麒麟KYLINOS2303系统上禁用新功能介绍页面的文章&#xff0c;在我们安装完系统登录后&#xff0c;会发现有新功能介绍这个界面&#xff0c;我们可以通…

《微信小程序开发从入门到实战》学习十六

第三章 开发第一个小程序 3.3 开发创建投票页面 3.3.2 修改模拟器中的启动页面 通过页面跳转的方式预览第二个页面内容不方便。 微信开发工具的工具栏有一个编译模式的设置&#xff1a; 选择“添加编译模式”&#xff0c; 加一个便于区分的名称&#xff0c;点击确定。 模拟…

PPT基础:编辑顶点

目录 编辑顶点对顶点的编辑对线段的编辑编辑顶点用法 编辑顶点 所在位置&#xff1a; 实质&#xff1a;是一种改变图像性质的操作 如何把一个圆形变成三角形&#xff1a;选中其中一个顶点&#xff0c;右键删除一个顶点&#xff1b;靠近某一条边&#xff0c;右键“拉伸弓形”即…

css实现原生form表单label必填选项红色*样式,以及js控制必填校验

文章目录 一、css实现原生form表单label必填选项红色*样式&#xff0c;以及js控制必填校验&#xff1f;二、实现方案参考原文 一、css实现原生form表单label必填选项红色*样式&#xff0c;以及js控制必填校验&#xff1f; 二、实现方案 1.css实现原生form表单label必填选项红色…

Centos(Linux)服务器安装Dotnet8 及 常见问题解决

1. 下载dotnet8 sdk 下载 .NET 8.0 SDK (v8.0.100) - Linux x64 Binaries 拿到 dotnet-sdk-8.0.100-linux-x64.tar.gz 文件 2. 把文件上传到 /usr/local/software 目录 mkdir -p /usr/local/software/dotnet8 把文件拷贝过去 mv dotnet-sdk-8.0.100-linux-x64.tar.gz /usr/loc…

【 OpenGauss源码学习 —— 列存储(update)】

列存储&#xff08;Insert&#xff09; 概述相关函数CStoreUpdate::ExecUpdate 函数JunkFilter 结构体CStoreInsert::BatchInsert 函数bulkload_rows::append_one_vector 函数bulkload_rows::append_in_column_orientation我函数 ExecVecUpdate 函数CStoreUpdate::EndUpdate 函…

Python3.7+PyQt5 pyuic5将.ui文件转换为.py文件、Python读取配置文件、生成日志

1.实际开发项目时&#xff0c;是使用Qt Designer来设计UI界面&#xff0c;得到一个.ui的文件&#xff0c;然后利用PyQt5安装时自带的工具pyuic5将.ui文件转换为.py文件&#xff1a; pyuic5 -o mywindow.py mywindow.ui #先是py文件名&#xff0c;再是ui文件名样式图 QT5 UI&am…