async、future、packaged_task、promise

一.async、future创建后台任务并返回值

希望线程返回一个结果
std::async是个函数模板,用来启动一个异步任务。什么叫“启动一个异步任务”,就是自动创建一个线程并开始执行对应的线程入口函数,它返回一个std::future对象,这个std::future对象里面就含有线程函数返回的结果,我们可以通过调用std::future对象的成员函数get()来获取结果。当调用future对象的get()成员函数时,会阻塞到这行,直到线程执行结束并返回,只能调用一次

异步任务和多线程的区别?
当我们在遇到需要长时间执行的任务时候,比如读取一个文件,远程服务调用。这些功能都会阻塞主线程,造成主线程卡死,从而造成一种软件崩溃的假象。多线程技术是实现异步任务的一种实现。

我们还可以额外地向std::async()传递一个参数,该参数类型是std::launch类型(枚举类型),达到一些特殊的目的。

  • std::launch::deferred: 表示线程入口函数调用被延迟到std::future的wait()或者get()函数调用时才执行。那如果wait()或者get()没有没调用,那么线程会执行吗?线程没有创建,是在主线程中进行调用的???(此处老师的演示是在主线程中执行了,我自己的实验这个入口函数没有被执行)

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

#include <bits/stdc++.h>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <future>
using namespace std;

class A{
    public:
    int mythread(int mypar){
        cout<<mypar<<endl;
        cout<<"mythread() start "<<"threadid = "<<this_thread::get_id()<<endl;
        chrono::milliseconds dura(50000); //定义一个5s的时间
        this_thread::sleep_for(dura);
        cout<<"mythread() end "<<"threadid = "<<this_thread::get_id()<<endl;
        return 5;
    }
};
int mythread(){
    cout<<"mythread() start "<<"threadid = "<<this_thread::get_id()<<endl;
    chrono::milliseconds dura(50000); //定义一个5s的时间
    this_thread::sleep_for(dura);
    cout<<"mythread() end "<<"threadid = "<<this_thread::get_id()<<endl;
    return 5;
}
int main()
{
    A myobj;
    int t = 12;
    cout<<"main() start "<<"threadid = "<<this_thread::get_id()<<endl;
    //future<int> result = async(mythread); //创建一个线程并执行,不会阻塞到这里
    future<int> result = async(launch::deferred,&A::mythread,ref(myobj),t); 
    cout<<"continue.....~"<<endl;
    int def = 0;
    //result.wait(); //等待线程返回,并不返回结果
   //cout<<result.get()<<endl; //阻塞在这里,等待mythread()线程执行完
    cout<<"I love China!!"<<endl;
    return 0;
}

二.packaged_task

目的:打包任务,把任务包装起来

std::packaged_task是个模板类,它的模板参数是各种可调用对象;通过std::packaged_task来把各种可调用对象包装起来,方便将来作为线程入口函数来调用。

packaged_task包装起来的可调用对象还可以直接调用,所以从这个角度来讲,packaged_task对象,也是一个可调用对象。

#include <bits/stdc++.h>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <future>
using namespace std;


 
int mythread(int mypar) //线程入口函数
{
	cout << mypar << endl;
	cout << "mythread2 start" << "threadid= " << std::this_thread::get_id() << endl; //打印线程id
 
	std::chrono::milliseconds dura(5000); //定一个5秒的时间
	std::this_thread::sleep_for(dura);  //休息一定时长
 
	cout << "mythread2 end" << "threadid= " << std::this_thread::get_id() << endl; //打印线程id
 
	return 5;
}

int main()
{
    cout << "main" << "threadid= " << std::this_thread::get_id() << endl;
    packaged_task<int(int)> mobj(mythread); //把函数mythread通过packaged_task包装起来
   // mobj(1);  //1)直接调用,并没有创建线程,相当于函数调用
    thread t1(ref(mobj), 1); //2)创建线程调用
    t1.join();
    future<int> result = mobj.get_future();//packaged_task和future绑定,拿到一个将来的值
    cout<<result.get()<<endl;
    return 0;
}

三.promise

std::promise 类模板,我们能够在某个线程中给它赋值,然后我们可以在其他线程中把这个值取出来用。

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

#include <bits/stdc++.h>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <future>
using namespace std;
 
void mythread(promise<int> &t, int calc) //线程入口函数
{
    //进行一系列复杂的操作
    calc++;
    std::chrono::milliseconds dura(5000); //定一个5秒的时间
	std::this_thread::sleep_for(dura);  //休息一定时长

    //计算出结果,将结果保存到promise对象中
    t.set_value(calc); 
}

void mythread2(future<int> &t){
    auto result = t.get();
	cout <<"mythread result = " << result<<endl;
}
int main()
{
    promise<int> m; 
    thread t1(mythread,ref(m),1);
    t1.join();
    //获取结果值
    future<int> result = m.get_future();  //promise和future绑定,拿到一个将来的值
    
    thread t2(mythread2,ref(result)); //future传递给其他线程
    t2.join();
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章