0
收藏
微博
微信
复制链接

thread、future、promise、packaged_task、async之间有什么关系?

2024-01-23 15:02
406

并发编程一般指多线程编程,C  11之后关于多线程编程有几个高级API:

  • std::thread

  • std::future

  • std::shared_future

  • std::promise

  • std::packaged_task

  • std::async

可能很多人都搞不清楚它们之前有什么联系,可以直接看这张图:

如果连它们是什么都不知道的朋友,可以先看看这个:https://mp.weixin.qq.com/s/rPjRTOTYK2SGr6WxgWI_Vg


从这张图我们可以大体看出来:

  • packaged_task ≈ promise   function

  • async ≈ thread   packaged_task

  • 通过promise的get_future()可拿到future

  • 通过future的share()可拿到shared_future


promise和future是线程之间的同步通道,类似于条件变量的封装,看它的使用:

#include


首先创建一个promise,通过promise可以拿到future,future有wait()和get()等方法,这种方法会阻塞当前线程,直到future的源promise调用了set_value,future的wait()只有阻塞功能,而get()方法不仅有阻塞功能,还能拿到set_value()设置的值。我举个多线程的示例:


#include


这段代码执行后会在两秒后输出100。这个结果就验证了上面啰嗦的promise的future的get()的阻塞和获取结果的能力。


注意:一个promise的set_value()只能调用一次,如果调用多次,就会throw exception,如果外部没catch exception,程序就会crash。


promise的阻塞功能还是蛮好用的,我在工程中就经常用到它。


介绍完promise,再来看看packaged_task:

#include


可以拿这段代码和上面那段promise的代码对比看看,可以得出结论:

packaged_task ≈ promise   function

promise只能set_value,不太好执行复杂的逻辑,有执行函数 阻塞的需求时,就可以考虑使用packaged_task。

可以思考一下,如果要你封装一个packaged_task,你会怎么做?


再看async:

#include

这里可以看到,使用了async后,连thread都不需要创建了,这也就验证了上面图中的结论:

async ≈ thread   packaged_task


这里请注意:async中的第一个参数我使用的是std::launch::async,只有当参数为std::launch::async时,函数才会异步执行。

参数还可以是std::launch::deferred,参数为这个时,函数不会异步执行,只有当对应的future调用了get时,函数才会执行,而且是在当前线程执行。

关于async有几个坑,我之前写过一篇文章,可以看这个:async的两个坑


介绍完async,再介绍下shared_future。

普通的future有个特点,它不能拷贝,只能移动,这就意味着只能有一个线程一个实例可以通过get()拿到对应的结果。

如果想要多个线程多个实例拿到结果,就可以使用shared_future,那怎么拿到shared_future,可以通过普通future的shared()方法。

#include

看到这里,大家应该明白thread、future、promise、packaged_task、async之间的关系了吧。

登录后查看更多
0
评论 0
收藏
侵权举报
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表凡亿课堂立场。文章及其配图仅供工程师学习之用,如有内容图片侵权或者其他问题,请联系本站作侵删。

热门评论0

相关文章

程序喵大人

分享C++、Rust技术

开班信息