type
status
date
slug
summary
tags
category
icon
password
Email
文章首发于我的个人博客:欢迎大佬们来逛逛
C++多线程编程项目源码:Github地址
处理带返回值的函数
有三种方法:
- async
- packaged_task
- promise
async
第一种方法是使用 async 函数。
步骤:
- 使用
async
创建线程处理函数
- 使用
.get()
获取返回值。
async函数具有两个属性
- launch::async(默认):表示创建线程处理函数并且立刻执行
- launch::defered:延期,当使用wait或者get的时候才会执行线程处理函数
async函数的返回值:
std::future
类型,通过调用其 get 方法获取返回值下面分别演示了普通函数与类的成员函数以及 defered 的作用:
packaged_task
第二种方法是使用 packaged_task 方法
步骤:
- 使用
packaged_task
来包装线程处理函数
- 然后将这个包装好的函数加入到线程
thread
中,并且执行线程处理函数
- 最后使用这个 packaged_task 调用
get_future
来获取 future,然后调用get
获取值。
package_task 函数包装语法:
要点:
- packaged_task 非常适合用于异步执行任务的时候。
- 它有点类似于std::function 函数包装器,都是把一个函数封装起来。
std::packaged_task
通常于 std::future
一起使用,std::future
是获取线程处理函数的返回值的方式。看示例代码:
- 使用
std::packaged_task
包装函数调用
task.get_future
来获取此任务的std::future
对象,以便往后任何时候获取线程处理的返回值。
std::packaged_task
是可移动的,但是不可拷贝。
std::future.wait
方法可以等待线程执行完毕。
- 使用
.get
获取值。
与std::function的区别
std::packaged_task的优势:
- 任务封装: std::packaged_task 主要用于将函数或可调用对象封装为一个可异步执行的任务。
- 与 std::future 结合使用: std::packaged_task 通常与 std::future 结合使用,通过调用 get_future() 获取一个与任务相关联的 std::future 对象,以便获取任务执行的结果。
- 可移动但不可拷贝: std::packaged_task 对象是可移动但不可拷贝的,因为它们通常与异步执行相关,而拷贝可能导致不确定的行为。
- 通常用于异步任务: 适用于需要在其他线程中执行的任务,通过异步执行来达到并发的效果。
std::function 的优势:
- 可调用对象容器: std::function 是一个通用的可调用对象容器,可以包装函数、函数对象、Lambda 表达式等,提供了一种统一的方式来操作这些可调用对象。
- 类型擦除: std::function 使用类型擦除的技术,允许将不同类型的可调用对象存储在同一个对象中。
- 可拷贝: std::function 对象是可拷贝的,因为它们的设计目的是为了提供通用性和灵活性。
- 不涉及异步: 通常用于需要在同一线程中调用的场景,不涉及异步任务的执行。
注意 std::function 是不涉及异步操作的,因此如果想要在线程处理后获取值,必须在同一线程中获取,result必须随时接收此返回值,而 std::future可以在任意时刻 .get 获取其值。
promise
第三种方法是使用 promise 类型
步骤:
- 传递
promise
类型的变量到线程处理函数中。
- 我们正常执行线程处理函数即可,无需使用return语句,在操作完成后把需要的值
set_value
设置为promise 的值。
- 然后使用
thread
创建并且执行线程处理函数。
- 然后我们就可以在外部使用 .
get_future
获取 future对象, 继而 .get
获取值。
这种方法的特点:
- 无需显示设置 return 语句
- 需要往线程处理函数添加一个额外的 promise 类型的参数。
例如这个是我们的线程处理函数,我们需要返回
num *3
, 但是现在我们添加一个promise 类型的参数(注意是引用),然后直接 set_value
即可,然后再外部就可以直接访问这个值了。- 返回线程处理函数的值:
这种方法也可以传递线程的值到另一个线程处理函数中:
有一个
testGetValueThread
线程函数,我们需要把刚才获取的 num*3 的值再传递进去,则可以在这个线程函数内调用 .get_future().get()
来传递参数。下面是两种方法,这里使用了函数重载作为线程处理函数,需要使用static_cast来避免重载歧义。
通过static_cast消除重载函数的歧义
- 作者:Yuleo
- 链接:https://www.helloylh.com/article/multithread3
- 声明:本文采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。