一.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;
}