C++并行开发9-async、future、packaged_task、promise

FengLY Lv3

std::future 使用

小试牛刀

一、 std::async、std::future创建后台任务并返回值 希望线程返回一个结果
std::async是一个函数模板,用来启动一个异步任务,启动一个异步任务之后,他返回一个future对象 什么是“启动一个异步任务”,
自动创建一个线程,并且开始执行对应的线程入口函数,他返回一个std::future对象。
这个std::future对象中就含有线程入口函数所返回的结果,我们可以通过调用future对象的成员函数get()来获取
std::future,通俗一点就是future中会保存一个值,将来可以拿到 需要注意的是get()函数方法只能使用一次

#include <iostream>
#include <thread>
#include <algorithm>
#include <vector>
#include <list>
#include <mutex>
#include <future>   //引入std::future头文件
using namespace std;

int my_thread() {  //线程入口函数
    cout << "mythread start" << " threadid is = " << std::this_thread::get_id() << endl;
    std::chrono::milliseconds dura(5000);  //休息了5s
    std::this_thread::sleep_for(dura);
    cout << "over " << endl;
    return 5;
}

int main() {
    // 一、 std::async、std::future创建后台任务并返回值
    // 希望线程返回一个结果
    // std::async是一个函数模板,用来启动一个异步任务,启动一个异步任务之后,他返回一个future对象
    // 什么是“启动一个异步任务”, 自动创建一个线程,并且开始执行对应的线程入口函数,他返回一个std::future对象。
    // 这个std::future对象中就含有线程入口函数所返回的结果,我们可以通过调用future对象的成员函数get()来获取
    // std::future,通俗一点就是future中会保存一个值,将来可以拿到

    cout << "main " << " threadid is = " << std::this_thread::get_id() << endl;
    std::future<int> result = std::async(my_thread);  //async:异步; 

    cout << "continue " << endl;

    cout << result.get() << endl;  //卡到这里一直到mythread执行完毕 只能调用一次

    cout << "主函数运行结束" << endl;

    return 0;
}

调用类成员函数,并且使用std::launch

#include <iostream>
#include <thread>
#include <algorithm>
#include <vector>
#include <list>
#include <mutex>
#include <future>   //引入std::future头文件
using namespace std;

class A {
public:
    int my_thread(int mypar) {  //线程入口函数
        cout << mypar << endl;
        cout << "mythread start" << " threadid is = " << std::this_thread::get_id() << endl;
        std::chrono::milliseconds dura(5000);  //休息了5s
        std::this_thread::sleep_for(dura);
        cout << "over " << endl;
        return 5;
    }

};


int main() {
    // 一、 std::async、std::future创建后台任务并返回值
    // 希望线程返回一个结果
    // std::async是一个函数模板,用来启动一个异步任务,启动一个异步任务之后,他返回一个future对象
    // 什么是“启动一个异步任务”, 自动创建一个线程,并且开始执行对应的线程入口函数,他返回一个std::future对象。
    // 这个std::future对象中就含有线程入口函数所返回的结果,我们可以通过调用future对象的成员函数get()来获取
    // std::future,通俗一点就是future中会保存一个值,将来可以拿到

    //我们可以向std::async传递std::launch(枚举类型)
    // a) std::launch::deferred表示线程入口函数被延迟到std::future的wait()或者get()函数调用时才执行,此时线程都没有创建
    // 并且实际上std::launch::deferred就没有创建新线程,是在主线程中调用的线程入口函数
    // b) std::launch::async调用了新线程,是默认使用的参数

    A a;

    cout << "main " << " threadid is = " << std::this_thread::get_id() << endl;
    //std::future<int> result = std::async(my_thread);  //async:异步; 
    std::future<int> result = std::async(std::launch::deferred, &A::my_thread, a, 100);  //async:异步; 

    cout << "continue " << endl;

    cout << result.get() << endl;  //卡到这里一直到mythread执行完毕 只能调用一次

    cout << "主函数运行结束" << endl;

    return 0;
}

std::launch 有async,和deferred
async会重新创建一个新的线程,但是deferred不会重新重建一个新的线程,只当函数运行到get或者wait的时候才会被执行;

使用std::packaged_task

二、packaged_task: 打包任务,把任务打包起来
是个类模板,他的模板参数是各种可以调用对象,通过std::packaged_task来把各种调用对象包装起来,方便作为线程入口函数

#include <iostream>
#include <thread>
#include <algorithm>
#include <vector>
#include <list>
#include <mutex>
#include <future>   //引入std::future头文件
using namespace std;

class A {
public:
    int my_thread(int mypar) {  //线程入口函数
        cout << mypar << endl;
        cout << "mythread start" << " threadid is = " << std::this_thread::get_id() << endl;
        std::chrono::milliseconds dura(5000);  //休息了5s
        std::this_thread::sleep_for(dura);
        cout << "over " << endl;
        return 5;
    }

};

int my_thread(int mypar) {  //线程入口函数
    cout << mypar << endl;
    cout << "mythread start" << " threadid is = " << std::this_thread::get_id() << endl;
    std::chrono::milliseconds dura(5000);  //休息了5s
    std::this_thread::sleep_for(dura);
    cout << "over " << endl;
    return 5;
}

int main() {
    // 二、std::packaged_task: 打包任务,把任务打包起来
    // 是个类模板,他的模板参数是各种可以调用对象,通过std::packaged_task来把各种调用对象包装起来,方便作为线程入口函数
    cout << "main " << " threadid is = " << std::this_thread::get_id() << endl;
    std::packaged_task<int(int)> mypt(my_thread);
    std::thread t1(std::ref(mypt), 1);
    t1.join();
    std::future<int> result = mypt.get_future();  //rsult保存my_thread的结果
    cout << result.get();

    cout << "主线程运行结束" << endl;
}

也可以使用lambda代替

int main() {

    cout << "main " << " threadid is = " << std::this_thread::get_id() << endl;
    /*std::packaged_task<int(int)> mypt(my_thread);*/
    //使用lambda表达式
    std::packaged_task<int(int)> mypt([](int mypar) {
        cout << mypar << endl;
        cout << "mythread start" << " threadid is = " << std::this_thread::get_id() << endl;
        std::chrono::milliseconds dura(5000);  //休息了5s
        std::this_thread::sleep_for(dura);
        cout << "over " << endl;
        return 5;
    });
    std::thread t1(std::ref(mypt), 1);
    t1.join();
    std::future<int> result = mypt.get_future();  //rsult保存my_thread的结果
    cout << result.get();

    cout << "主线程运行结束" << endl;
}

packaged_task也可以在main函数中直接使用

    std::packaged_task<int(int)> mypt([](int mypar) {
        cout << mypar << endl;
        cout << "mythread start" << " threadid is = " << std::this_thread::get_id() << endl;
        std::chrono::milliseconds dura(5000);  //休息了5s
        std::this_thread::sleep_for(dura);
        cout << "over " << endl;
        return 5;
    });
    //std::thread t1(std::ref(mypt), 1);
    //t1.join();
    mypt(100);
    std::future<int> result = mypt.get_future();  //rsult保存my_thread的结果
    cout << result.get();

在容器中使用std::packaged_task

std::vector<std::packaged_task<int(int)>> mytask;

int main() {
    cout << "main " << " threadid is = " << std::this_thread::get_id() << endl;
    std::packaged_task<int(int)> mypt([](int mypar) {
        cout << mypar << endl;
        cout << "mythread start" << " threadid is = " << std::this_thread::get_id() << endl;
        std::chrono::milliseconds dura(5000);  //休息了5s
        std::this_thread::sleep_for(dura);
        cout << "over " << endl;
        return 5;
    });
    mytask.push_back(std::move(mypt));
    std::packaged_task<int(int)> mypt2;
    auto iter = mytask.begin();
    mypt2 = std::move(*iter);
    //mypt2 = std::move(*iter);

    mytask.erase(iter);
    mypt2(123);

    std::future<int> result = mypt2.get_future();  //rsult保存my_thread的结果
    cout << result.get();

    cout << "主线程运行结束" << endl;
    return 0;
}

使用std::promise

#include <iostream>
#include <thread>
#include <algorithm>
#include <vector>
#include <list>
#include <mutex>
#include <future>   //引入std::future头文件
using namespace std;

// 三、 std::promise, 类模板
// 我们能够在某个线程中给它赋值,然后再在其他线程中把这个值取出来

void mythread(std::promise<int>& temp, int calc) {
    // 做一些运算
    calc++;
    calc *= 10;

    std::chrono::milliseconds dura(5000); 
    std::this_thread::sleep_for(dura);

    int result = calc;
    temp.set_value(result); //结果已经保存到了temp中
}

int main()
{
    std::promise<int> myprom;
    std::thread t1(mythread, std::ref(myprom), 180);
    t1.join();

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

    cout << "result = " << result << endl;

    cout << "主线程结束 " << endl;
}

两个类型之间的传递

#include <iostream>
#include <thread>
#include <algorithm>
#include <vector>
#include <list>
#include <mutex>
#include <future>   //引入std::future头文件
using namespace std;

// 三、 std::promise, 类模板
// 我们能够在某个线程中给它赋值,然后再在其他线程中把这个值取出来

void mythread(std::promise<int>& temp, int calc) {
    // 做一些运算
    calc++;
    calc *= 10;

    std::chrono::milliseconds dura(5000); 
    std::this_thread::sleep_for(dura);

    int result = calc;
    temp.set_value(result); //结果已经保存到了temp中
}


void mythread2(std::future<int>& temp) {
    auto result = temp.get();
    cout << "mythread2 result is" << result << endl;
}
int main()
{
    std::promise<int> myprom;
    std::thread t1(mythread, std::ref(myprom), 180);
    t1.join();

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

    std::thread t2(mythread2, std::ref(fu1));
    t2.join();

    cout << "主线程结束 " << endl;
}

小结

  • Title: C++并行开发9-async、future、packaged_task、promise
  • Author: FengLY
  • Created at : 2023-06-18 22:40:09
  • Updated at : 2023-06-18 22:58:11
  • Link: https://zhouaq.com/2023/06/18/C++并行开发9-async、future、packaged_task、promise/
  • License: This work is licensed under CC BY-NC-SA 4.0.
Comments