文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

Thread、Future、Promise、Packaged_task、Async之间有什么关系?

2024-12-01 19:24

关注

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

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

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

#include <future>
#include <iostream>
#include <thread>

int main() {
std::promise<bool> prom;
std::future<bool> f = prom.get_future();
prom.set_value(true);
std::cout << f.get() << std::endl;
}

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

#include <future>
#include <iostream>
#include <thread>

int main() {
std::promise<int> prom;
auto f = prom.get_future();
std::thread t(
[](std::promise<int> p) {
std::this_thread::sleep_for(std::chrono::seconds(2));
p.set_value(100);
},
std::move(prom));
std::cout << f.get() << std::endl;
if (t.joinable()) t.join();
}

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

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

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

介绍完promise,再来看看packaged_task:

#include <future>
#include <iostream>
#include <thread>
int main() {
std::packaged_task<int(int, int)> task([](int a, int b) { return a + b; });
auto f = task.get_future();
std::thread t(std::move(task), 1, 2);
std::cout << f.get() << std::endl;
if (t.joinable()) t.join();
}

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

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

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

再看async:

#include <future>
#include <iostream>
#include <thread>
int main() {
auto f = std::async(
std::launch::async, [](int a, int b) { return a + b; }, 1, 2);
std::cout << f.get() << std::endl;
}

这里可以看到,使用了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 <future>
#include <iostream>
#include <thread>
int main() {
std::promise<int> prom;
auto fu = prom.get_future();
auto shared_fu = fu.share();
auto f1 = std::async(std::launch::async, [shared_fu]() { std::cout << shared_fu.get() << std::endl; });
auto f2 = std::async(std::launch::async, [shared_fu]() { std::cout << shared_fu.get() << std::endl; });
prom.set_value(102);
f1.get();
f2.get();
}

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

来源:程序喵大人内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯