• 九、std::async异步线程


    std::async、std::future创建后台任务并返回值

    std::async是一个函数模板,用来启动一个异步任务,启动起来一个异步任务之后,它返回一个std::future对象,这个对象是个类模板。

    异步任务:就是自动创建一个线程,并开始 执行对应的线程入口函数,它返回一个std::future对象,这个std::future对象中就含有线程入口函数所返回的结果,我们可以通过调用future对象的成员函数get()来获取结果。

    “future”将来的意思,也有人称呼std::future提供了一种访问异步操作结果的机制,就是说这个结果你可能没办法马上拿到,但是在不久的将来,这个线程执行完毕的时候,你就能够拿到结果了,所以,大家这么理解:future中保存着一个值,这个值是在将来的某个时刻能够拿到。

    std::future对象的get()成员函数会等待线程执行结束并返回结果,拿不到结果它就会一直等待,有点像join(),但它可以获取结果。

     1 #include <thread>
     2 #include <iostream>
     3 #include <list>
     4 #include <map>
     5 #include <mutex>
     6 #include <future>
     7 using namespace std;
     8 class A {
     9 public:
    10     int mythread(int mypar) {
    11         cout << mypar << endl;
    12         return mypar;
    13     }
    14 };
    15  
    16  
    17 int mythread() {
    18     cout << "mythread() start" << "threadid = " << std::this_thread::get_id() << endl;
    19     std::chrono::milliseconds dura(5000);
    20     std::this_thread::sleep_for(dura);
    21     cout << "mythread() end" << "threadid = " << std::this_thread::get_id() << endl;
    22     return 5;
    23 }
    24  
    25  
    26 int main() {
    27     A a;
    28     int tmp = 12;
    29     cout << "main" << "threadid = " << std::this_thread::get_id() << endl;
    30     std::future<int> result1 = std::async(mythread);
    31     cout << "主子并行........" << endl;
    32     cout << result1.get() << endl; //卡在这里等待mythread()执行完毕,拿到结果,只能调用一次
    33     
    34     //类成员函数
    35     std::future<int> result2 = std::async(&A::mythread, &a, tmp); //参数是对象引用才能保证线程里执行的是同一个对象
    36     cout << result2.get() << endl;
    37     cout << "good luck" << endl;
    38     return 0;
    39 }

    通过向std::async()传递一个参数,改参数是std::launch类型(枚举类型),来达到一些特殊的目的:

    1、std::lunch::deferred:

      表示线程入口函数调用被延迟到,std::future的wait()或者get()函数调用时才执行;

      如果wait()或者get()没有被调用,则不会执行。实际上根本就没有创建。(并不是并行执行,而是在主线程中调用的线程入口函数)。

    2、std::launch::async

      在调用async函数的时候就开始创建线程。async()这个函数默认用的就是std::launch::async标记。

    std::packaged_task:打包任务,把任务包装起来。

    类模板,它的模板参数是各种课调用对象,通过packaged_task把各种可调用对象包装起来,方便将来作为线程入口函数。(算了,不是很懂!)

     1 #include <thread>
     2 #include <iostream>
     3 #include <list>
     4 #include <map>
     5 #include <mutex>
     6 #include <future>
     7 using namespace std;
     8  
     9 int mythread(int mypar) {
    10     cout << mypar << endl;
    11     cout << "mythread() start" << "threadid = " << std::this_thread::get_id() << endl;
    12     std::chrono::milliseconds dura(5000);
    13     std::this_thread::sleep_for(dura);
    14     cout << "mythread() end" << "threadid = " << std::this_thread::get_id() << endl;
    15     return 5;
    16 }
    17  
    18  
    19 int main() {
    20     int tmp = 12;
    21     cout << "main" << "threadid = " << std::this_thread::get_id() << endl;
    22     std::packaged_task<int(int)> mypt(mythread); //我们把函数mythread通过packaged_task包装起来
    23     std::thread t1(std::ref(mypt), 1);
    24     t1.join();
    25     std::future<int> result = mypt.get_future(); 
    26     //std::future对象里包含有线程入口函数的返回结果,这里result保存mythread返回的结果。
    27     cout << result.get() << endl;
    28     cout << "good luck" << endl;
    29     return 0;
    30 }

    std::promise,类模板

    我们能够在某个线程中给它赋值,然后我们可以在其他线程中,把这个值取出来

     1 #include <thread>
     2 #include <iostream>
     3 #include <list>
     4 #include <map>
     5 #include <mutex>
     6 #include <future>
     7 using namespace std;
     8  
     9 void mythread(std::promise<int> &tmp, int clac) {
    10     cout << "mythread() start" << "threadid = " << std::this_thread::get_id() << endl;
    11     std::chrono::milliseconds dura(5000);   
    12     std::this_thread::sleep_for(dura);
    13     cout << "mythread() end" << "threadid = " << std::this_thread::get_id() << endl;
    14     int result = clac;
    15     tmp.set_value(result); //结果保存到了tmp这个对象中
    16     return;
    17 }
    18  
    19 vector<std::packaged_task<int(int)>> task_vec;
    20  
    21 int main() {
    22     std::promise<int> myprom;
    23     std::thread t1(mythread, std::ref(myprom), 180);
    24     t1.join(); //在这里线程已经执行完了
    25     std::future<int> fu1 = myprom.get_future(); //promise和future绑定,用于获取线程返回值
    26     auto result = fu1.get();
    27     cout << "result = " << result << endl;
    28 }

    总结:通过promise保存一个值,在将来某个时刻我们通过吧一个future绑定到这个promise上,来得到绑定的值

    std::future 的成员函数

    wait_for():主线程等你x秒,希望你返回值。

      std::future_status::timeout:返回超时

       std::future_status::ready:准时返回

       std::future_status::deferred:线程延迟执行(实际并没有创建子线程,而是在主线程中执行)

     1 #include <thread>
     2 #include <iostream>
     3 #include <list>
     4 #include <map>
     5 #include <mutex>
     6 #include <future>
     7 using namespace std;
     8  
     9 int mythread() {
    10     cout << "mythread() start" << "threadid = " << std::this_thread::get_id() << endl;
    11     std::chrono::milliseconds dura(5000);
    12     std::this_thread::sleep_for(dura);
    13     cout << "mythread() end" << "threadid = " << std::this_thread::get_id() << endl;
    14     return 5;
    15 }
    16  
    17  
    18 int main() {
    19     A a;
    20     int tmp = 12;
    21     cout << "main" << "threadid = " << std::this_thread::get_id() << endl;
    22     std::future<int> result = std::async(mythread);
    23     cout << "continue........" << endl;
    24     //cout << result1.get() << endl; //卡在这里等待mythread()执行完毕,拿到结果
    25     std::future_status status = result.wait_for(std::chrono::seconds(1));
    26     if (status == std::future_status::timeout) {
    27         //超时:表示线程还没有执行完
    28         cout << "超时了,线程还没有执行完" << endl;
    29     }
    30     //类成员函数
    31     return 0;
    32 }

    std::shared_future:也是个类模板

    std::future的 get() 成员函数是转移数据(移动语义),只能调用一次

      auto res=tmp.get();将相当于tmp中的返回值移动到res中了,tmp的返回值为空了。

    std::shared_future 的 get() 函数是赋值数据

      如果我多个线程都想要get()的返回值怎么办呢?就是这个了

     1 #include <thread>
     2 #include <iostream>
     3 #include <list>
     4 #include <map>
     5 #include <mutex>
     6 #include <future>
     7 using namespace std;
     8  
     9 int mythread() {
    10     cout << "mythread() start" << "threadid = " << std::this_thread::get_id() << endl;
    11     std::chrono::milliseconds dura(5000);
    12     std::this_thread::sleep_for(dura);
    13     cout << "mythread() end" << "threadid = " << std::this_thread::get_id() << endl;
    14     return 5;
    15 }
    16  
    17 int mythread2(std::shared_future<int> &res) {
    18     cout << "mythread2() start" << "threadid = " << std::this_thread::get_id() << endl;
    19     auto myresult3 = res.get();
    20     cout << "mythread2() end" << "threadid = " << std::this_thread::get_id() << endl;
    21     return 5;
    22 }
    23  
    24 int main() {
    25     int tmp = 12;
    26     cout << "main" << "threadid = " << std::this_thread::get_id() << endl;
    27     std::packaged_task<int()> mypt(mythread);
    28     std::thread t1(std::ref(mypt));
    29     std::future<int> result = mypt.get_future();
    30     //std::shared_future<int> result_s(std::move(result));
    31     bool ifcanget = result.valid(); //判断future 中的值是不是一个有效值
    32     std::shared_future<int> result_s(result.share()); //执行完毕后result_s里有值,而result里空了
    33     t1.join();
    34     
    35     auto myresult1 = result_s.get();
    36     auto myresult2 = result_s.get();
    37  
    38     std::thread t2(std::ref(mythread2), std::ref(result_s));
    39     t2.join();
    40     cout << "good luck" << endl;
    41     return 0;
    42 }
    心之所愿,永不相忘
  • 相关阅读:
    Oralce中备份,还原数据库
    Linux基础--目录了解以及安装后的优化
    PHP学习之旅——PHP环境搭建
    在虚拟机上安装Linux系统
    Hibernate 命名查询
    MyBatis入门案例
    MyBatis中关于别名typeAliases的设置
    SpingMvc中的异常处理
    无意之间发现的Servlet3.0新特性@WebServlet
    SpringMvc核心流程以及入门案例的搭建
  • 原文地址:https://www.cnblogs.com/zgll/p/15305754.html
Copyright © 2020-2023  润新知