• C++并发与多线程学习笔记--async、future、packaged_task、promise


    • async
    • future
    • packaged_task
    • promise

    async

    std:async 是个函数,用来启动一个异步任务,启动起来一个异步任务之后,返回一个std::futre对象,启动一个异步任务,就是自动创建一个线程并开始执行对应的线程入口函数,它返回一个std::future对象,这个std::future对象里面就含有线程入口函数返回的结果。可以通过调用future对象的成员函数get来获取结果。

    "future" 提供了一种访问异步操作结果的机制,程序运行的结果,可能没有办法马上拿到。可能需要一定时间才能返回结果。在线程执行完毕的时候,就能够拿到结果。所以大家这么理解,future里会保存一个值。

    例子:

    引入一个头文件

    #include<future>
    

     需要执行的函数,线程入口函数

    int mythread()
    {
    cout << "my thread start, and thread id is " << std::this_thread::get_id() <<endl;
    std::chrono::milliseconds dura(500);
    std::this_thread::sleep_for(dura);
    cout << "my thread end, and thread id is " << std::this_thread::get_id() <<endl;
    
    return 5;
    
    }
    

      在main中:

    	cout << "Main Thread End!!! " <<std::this_thread::get_id() <<endl;
    	
    	std::future<int> result = std::async(mythread);
    
    	cout << "continue..." << endl;
    
    	int def = 0;
    	def = 0;
    	cout << result.get() << endl;
    	cout << "Main thread end" << endl;
    

      当执行到get的时候,系统会卡在这里,一直等待线程执行完毕。线程执行完毕之后,返回。future里有个标记,标记当前的线程已经执行完毕,流程才能继续往下走。绑定关系,future和async创建的线程绑定到一起,一定要等待线程执行完了,程序才能往下执行。

    future

    get函数不拿到 future的返回值,就卡在这里等待拿值,必须要保证和future有关的函数一定要有返回值。

    future中还有一个wait(),等待线程返回,本身并不返回结果。 join();

    程序中如果同时写多个get函数,那么就会报错,get只能调用一次!

    在std::thread 用类的成员函数来作为线程的入口函数,用async也能用类的成员函数来作为线程的入口函数。

    std::future<int> result = std::async(&class::method, &obj, para1)
    

     从第三个参数开始,才是成员函数对应的参数。第二个参数是一个对象引用,才能保证线程里面用的是同一个对象,线程里面当执行函数的时候仍然对应的是那个对象。

    std::future<int> result = std::async(std::launch::deferred, &class::method, &obj, para1);
    
    std::future<int> result = std::async(std::launch::async, &class::method, &obj, para1);
    

      

    如果新建了future对象之后,不用get()和wait(),线程依然会运行,线程运行结束后,程序退出。

    get()成员函数等待线程执行结束后返回结果,我们通过额外向std::async()传递一个参数,该参数类型是std::launch类型(枚举类型)来达到一些特殊的目的。

    a)std::launch::deferred:表示线程入口函数调用被延迟到std::future的wait()或者get()函数调用时才执行。实际上线程根本没有被创建。

    b) std::launch::async,在调用的时候就开始创建线程,不会等到get().

    两个标记不能一起使用,用的时候必须要搞明白这些标记的含义。

    packaged_task

    std::packaged_task:打包任务,或者说将任务包装起来,这也是一个类模板。模板参数是各种可调用参数,通过packaged_task可以把各种可调用对象包装起来,方便将来作为线程入口函数作为调用。

    在main函数中,相当于包装了一个函数,<int(int)> 返回值(参数),实参就是入口函数,可调用对象。我们

    std::packaged_task<int(int)>  mypt(mythread);
    

    把函数mythread通过如下写法调用:

    std::thread t1(std::ref(mypt), 1);
    

     只不过线程创建方法是包装起来的线程入口函数,线程直接开始执行,第二个参数1,作为线程入口函数的参数,作为mythread的入口参数。通过future取结果

    std::future<int> result = mypt.get_future();
    

      只要绑定之后,future里面保存的就是mypt里面的值。std::future对象里包含有线程入口函数的返回结果,这里result保存mythread。

    packaged_task 包装起来的可调用对象还可以直接调用。

    promise

    std::promise这个也是一个类模板,作用是能够在某个线程中给它赋值,然后把这个值取出来。在线程中进行一个很复杂的运算,然后拿到运算结果。

    void mythread(std::promise<int> &tmp, int calc);
    

      可以在函数中做一系列复杂的操作,然后做其他运算,整整花费了5s,休息了一定时间,结果可以保存下来,然后

    int result = calc;
    tmp.set_value(result); //将结果保存并返回
    

      结果保存到了tmp这个对象中,在main中声明一个std::promise对象,可以保存这个值,保存的值为int类型

    std::promise<int> myprom;
    std::thread t1(mythread, std::ref(myprom), para);
    
    //然后等线程执行完
    t1.join();
    

      获取结果可以用到其他线程中去。

    std::future<int> fu1 = myprom.get_future(); //promise和future绑定用于获取线程返回值
    

      如果前面join了后面get能够马上拿到这个值。

    auto result = fu1.get();
    

      

  • 相关阅读:
    beta冲刺5
    beta冲刺4
    beta冲刺3
    beta冲刺2
    [LeetCode] 10. Regular Expression Matching(正则匹配)
    [LeetCode] 32. Longest Valid Parentheses(最长合法括号对)
    [LeetCode] 4. Median of Two Sorted Arrays.(两个有序数组的中位数)
    [LeetCode] 45. Jump Game Ⅱ(跳跃游戏之二)
    [LeetCode] 41. First Missing Positive(第一个缺失的正数)
    [LeetCode] 124. Binary Tree Maximum Path Sum(二叉树的最大路径和)
  • 原文地址:https://www.cnblogs.com/rynerlute/p/11846171.html
Copyright © 2020-2023  润新知