• C++多线程 task--std::promise和std::future


    0 引言

    本文主要讲解C++11/14/17中所提供的应用于多线程编程中的Task机制。

    Task可由如下几部分取得

    • std::async
    • std::packaged_task
    • std::promise和std::future

    而本文主要讲解std::promise和std::future相关的内容。

    std::promise和std::future通过一个数据管道进行交流,可以将std::promise看作生产者,std::future看作消费者,其两者形成如下的方式交互

    1 std::promise 

    std::promise本身是一个模版类,通过std::promise可以像数据管道中设置value,异常和相应的通知信息。

    std::promise提供了如下接口

    1. get_future() // 返回相应的future
    2. set_value() // 设置一个相应的值
    3. set_exception() // 设置一个异常
    4. set_value_at_thread_exit() // 设置一个值,当线程退出时,promise使数据管道中相应值的状态变为ready
    5. set_exception_at_thread_exit()

    如果std::promise设置值或者异常超过一次,那么会抛出std::future_error异常。

    2 std::future

    std::future本身是一个模版类,且其是不可拷贝对象, 可类比std::unique_ptr, 对其所管理的资源具有独占权。

    通过std::future,你可以

    • 从std::promise获得相应的值
    • 询问std::promise是否将值设置为可用
    • 等待std::promise的通知。这个等待可以设置一个相对时间间隔或者一个绝对时间
    • 创建一个共享的future(std::shared_future)

    std::future提供了如下主要接口

    1. share() // 返回一个std::shared_future
    2. get() // 从数据管道获得一个值或者异常
    3. valid() // 检查共享状态是否有效,当调用完get接口后,该函数返回false
    4. wait() // 等待结果
    5. wait_for() // 等待结果,这个接口会等待一个时间间隔,其返回值为std::future_status
    6. wait_until() // 等待结果,该接口会等待到一个绝对时间点,返回值为std::future_status

    3 std::future_status

    由上述知,future的wait_for和wait_until接口的返回值为std::future_status. 在C++11标准中,该值定义如下

    1. enum class future_status {
    2. ready,
    3. timeout,
    4. deferred
    5. };

    其相应的描述如下所示

    ready: 数据管道中的结果已经ready,也即可用

    timeout: 数据管道中的数据不可用,且wait等待时间已经到达

    deferred: 接口被延迟执行,也即还未开始

    4 示例代码

    本部分代码部分来自《C++ Concurrency in Action》,其具体示例如下所示

    1. #include <iostream>
    2. #include <future>
    3. #include <exception>
    4. #include <thread>
    5. void setval(std::promise<int>& p ,int a) {
    6. try {
    7. if (a == 0) {
    8. throw std::runtime_error("set value 0 not perimted");
    9. } else {
    10. // 设置相应的值
    11. p.set_value(a);
    12. }
    13. } catch(...) {
    14. // 设置异常,std::current_exception捕获当前异常
    15. p.set_exception(std::current_exception());
    16. }
    17. }
    18. int main() {
    19. std::promise<int> prom;
    20. auto fut = prom.get_future();
    21. std::thread t1(setval, std::ref(prom), 0);
    22. try {
    23. std::cout << "fut get value: " << fut.get() << "\n";
    24. } catch(std::exception& ptr) {
    25. std::cout << ptr.what() << "\n";
    26. }
    27. t1.join();
    28. return 0;
    29. }

    注意:在linux平台需要加上 -lpthread进行相应的构建。

    上述相应的输出如下所示

    fut get value: set value 0 not perimted

    5 总结

    本文总结了std::promise和std::future的相关概念及其使用。std::promise和std::future一般需要成对出现,用于构建C++多线程中Task。

    std::promise和std::future不需要锁等同步措施,其内部本身进行了相应的同步,其使用比mutex要简单方便。

  • 相关阅读:
    自己公司开发的ERP系统,怎么对接京东,淘宝等这些电商平台?
    Android Studio 新版本 Logcat 速查
    工程化:Plugin 介绍
    ElasticSearch学习笔记(三)
    基于机器学习之模型树短期负荷预测(Matlab代码实现)
    分布式事务保姆级教程
    AJAX——跨域问题
    Hadoop
    蓝桥杯python考级整理
    软考报名季,软考高级应该怎么选?
  • 原文地址:https://blog.csdn.net/qls315/article/details/125470427