• C++11 异步操作future和aysnc


    目录

    C++11异步操作的4个接口

    1. std::aysnc和std::future 

     std::future和std::aysnc的使用Demo

    2. std::packaged_task

    std::packaged_task的使用Demo

    3. std::promise

    std::promise的使用Demo

    总结


    C/C++Linux服务器开发/后台架构师【零声教育】-学习视频教程-腾讯课堂

    C++11异步操作的4个接口

    std::future : 异步指向某个任务,然后通过future特性去获取任务函数的返回结果(把一个任务放入线程池运行,然后可以获取返回结果)
    std::aysnc: 异步运行某个任务函数
    std::packaged_task:将任务和feature绑定在一起的模板,是一种封装对任务的封装(线程池)
    std::promise:承诺(线程1设置了某个值,通知另外的线程2)

    1. std::aysncstd::future 

            std::future期待一个返回,从一个异步调用的角度来说,future更像是执行函数的返回值,C++标准库使用std::future为一次性事件建模,如果一个事件需要等待特定的一次性事件,那么这线程可以获取一个future对象来代表这个事件

            异步调用往往不知道何时返回,但是如果异步调用的过程需要同步,或者说后一个异步调用需要使用前一个异步调用的结果。这个时候就要用到future。把future当做异步函数的返回值。

            线程可以周期性的在这个future上等待一小段时间,检查future是否已经ready,如果没有,该线程可以先去做另一个任务,一旦future就绪,该future就无法复位(无法再次使用这个future等待这个事件),所以future代表的是一次性事件。

    future的类型

    在库的头文件中声明了两种future,唯一future(std::future)和共享future(std::shared_future)。

    这两个是参照std::unique_ptr和std::shared_ptr设立的,前者的实例是仅有的一个指向其关联事件的实例,而后者可以有多个实例指向同一个关联事件,当事件就绪时,所有指向同一事件的std::shared_future实例会变成就绪。

    future的使用

    跟thread类似,async允许你通过将额外的参数添加到调用中,来将附加参数传递给函数。如果传入的函数指针是某个类的成员函数,则还需要将类对象指针传入(直接传入,传入指针,或者是std::ref封装)。

    默认情况下,std::async是否启动一个新线程,或者在等待future时,任务是否同步运行都取决于你给的参数。这个参数为std::launch类型

    1. std::launch::async,表明函数会在创建的新线程上运行。
    2. std::launch::defered表明该函数会被延迟调用,直到在future上调用get()或者wait()为止。
    3. std::launch::sync = std::launch::defered,表明该函数会被延迟调用

        4.std::launch::any = std::launch::defered | std::launch::async,表明该函数会被延迟调用,调用时在新线程上运行

     std::future和std::aysnc的使用Demo

    1. //future
    2. #include <iostream>
    3. #include <future>
    4. #include <thread>
    5. using namespace std;
    6. int find_result_to_add()
    7. {
    8. std::this_thread::sleep_for(std::chrono::seconds(5)); // 用来测试异步延迟的影响
    9. std::cout << "find_result_to_add" << std::endl;
    10. return 1 + 1;
    11. }
    12. int find_result_to_add2(int a, int b)
    13. {
    14. std::this_thread::sleep_for(std::chrono::seconds(5)); // 用来测试异步延迟的影响
    15. return a + b;
    16. }
    17. void do_other_things()
    18. {
    19. std::cout << "do_other_things" << std::endl;
    20. // std::this_thread::sleep_for(std::chrono::seconds(5));
    21. }
    22. int main()
    23. {
    24. // std::future<T> std::async是异步线程
    25. //三种方式
    26. std::future<int> result = std::async(std::launch::async, find_result_to_add); //表明函数会在自己创建的线程上运行,不会阻塞当前线程
    27. // std::future<decltype (find_result_to_add())> result = std::async(find_result_to_add);
    28. // auto result = std::async(find_result_to_add); // 推荐的写法
    29. do_other_things();
    30. std::cout << "result: " << result.get() << std::endl; // 延迟是否有影响? 阻塞等待find_result_to_add返回值
    31. //需要传递参数
    32. // std::future<decltype(find_result_to_add2(int, int))> result2 = std::async(find_result_to_add2, 10, 20); //错误
    33. std::future<decltype (find_result_to_add2(0, 0))> result2 = std::async(find_result_to_add2, 10, 20);
    34. // auto result2 = std::async(find_result_to_add2, 10, 20); // 推荐的写法
    35. std::cout << "result2: " << result2.get() << std::endl; // 延迟是否有影响? 阻塞等待find_result_to_add2返回值
    36. std::cout << "main finish" << endl;
    37. return 0;
    38. }

     

     

    2. std::packaged_task

            如果说std::async和std::feature还是分开看的关系的话,那么std::packaged_task就是将任务和feature绑定在一起的模板,是一种封装对任务的封装。

            可以通过std::packaged_task对象获取任务相关联的feature,调用get_future()方法可以获得std::packaged_task对象绑定的函数的返回值类型的future。std::packaged_task的模板参数是函数签名。

    std::packaged_task的使用Demo

    1. //-package_task
    2. #include <iostream>
    3. #include <future>
    4. #include <thread>
    5. using namespace std;
    6. int add(int a, int b, int c)
    7. {
    8. std::this_thread::sleep_for(std::chrono::seconds(2));
    9. std::cout << "call add\n";
    10. return a + b + c;
    11. }
    12. void do_other_things()
    13. {
    14. std::cout << "do_other_things" << std::endl;
    15. }
    16. int main()
    17. {
    18. std::packaged_task<int(int, int, int)> task(add); // 1. 封装任务,还没有运行
    19. // std::this_thread::sleep_for(std::chrono::seconds(2)); // 用来测试异步延迟的影响
    20. do_other_things();
    21. std::future<int> result = task.get_future(); // 这里运行吗?这里只是获取 future
    22. // 这里才真正运行
    23. task(1, 1, 2); //必须要让任务执行,否则在get()获取future的值时会一直阻塞
    24. std::cout << "result:" << result.get() << std::endl;
    25. std::cout << "end" << std::endl;
    26. return 0;
    27. }

     

    3. std::promise

            std::promise提供了一种设置值的方式,它可以在这之后通过相关联的std::future对象进行读取。换种说法,之前已经说过std::future可以读取一个异步函数的返回值了,那么这个std::promise就提供一种方式手动让future就绪 

            线程在创建promise的同时会获得一个future,然后将promise传递给设置他的线程,当前线程则持有future,以便随时检查是否可以取值。 

    std::promise的使用Demo

    1. //promise
    2. // std::promise和std::future配合,可以在线程之间传递数据。
    3. #include <future>
    4. #include <string>
    5. #include <thread>
    6. #include <iostream>
    7. using namespace std;
    8. void print1(std::promise<std::string>& p)
    9. {
    10. std::cout << "print1 sleep" << std::endl;
    11. std::this_thread::sleep_for(std::chrono::seconds(1));
    12. p.set_value("set string"); // 相当于返回future的结果
    13. }
    14. void print2(std::promise<int>& p)
    15. {
    16. std::cout << "print2 sleep" << std::endl;
    17. p.set_value(1);
    18. }
    19. void do_some_other_things()
    20. {
    21. std::cout << "do_some_other_things" << std::endl;
    22. }
    23. int main()
    24. {
    25. std::cout << "main1 -------------" << std::endl;
    26. std::promise<std::string> promise; // 注意类型:
    27. std::future<std::string> result = promise.get_future(); // future
    28. std::thread t(print1, std::ref(promise)); // 线程设置 传引用std::ref
    29. do_some_other_things();
    30. std::cout << "wait get result" << std::endl;
    31. std::cout <<"result " << result.get() << std::endl; // 在主线程等待 promise的返回 result set string
    32. t.join();
    33. std::cout << "\n\nmain2 -------------" << std::endl;
    34. std::promise<int> promise2;
    35. std::future<int> result2 = promise2.get_future();
    36. std::thread t2(print2, std::ref(promise2));
    37. do_some_other_things();
    38. std::cout << "result2 " << result2.get() << std::endl;
    39. t2.join();
    40. return 0;
    41. }

    总结

            future的表现为期望,当前线程持有future时,期望从future获取到想要的结果和返回,可以把future当做异步函数的返回值。

            promise是一个承诺,当线程创建了promise对象后,这个promise对象向线程承诺他必定会被人设置一个值,和promise相关联的future就是获取其返回的手段。

  • 相关阅读:
    linux 清除卸载jenkins
    Android应用集成RabbitMQ消息处理指南
    将 springboot应用部署到 docker环境
    securecrt设置字体颜色
    卷积神经网络的训练算法,卷积神经网络算法实现
    SoftwareTest8 - 怎样测试一个系统的性能 ?
    网安入门17-XSS(打Cookie)
    节流(Throttle)和防抖(Debounce)
    【无标题】软件测试自动化“领导者”SmartBear举办首场中国线上研讨会:洞悉全球自动化测试走向,探讨降本增效之策
    什么是P问题、NP问题和NPC问题
  • 原文地址:https://blog.csdn.net/kakaka666/article/details/128008109