一、std::async、std::future创建后台任务并返回值
- std::async:是一个函数模板,用来启动一个异步任务,启动起来一个异步任务之后,它会返回一个std::future对象
- std::future:是一个类模板,std::future对象里面就含有线程入口函数所返回的结果,我们可以调用future对象的成员函数get来得到结果。future含有“将来的意思”,有人也称呼std::future提供了一种访问异步操作结果的机制,就是说这个结果没有办法马上拿到,但不久的将来,等线程执行完毕的时候,就能拿到结果了。
- 异步任务:自动创建一个线程并开始执行对应的线程入口函数
- std::launch:是一个枚举类型,向std::async()传递一个该参数。可以表示不同的意义:
a)std::launch::deferred:表示线程入口函数调用被延迟到std::future的wait()或者get()函数调用时才执行,并且是直接在主线程中执行线程入口函数,相当于是一个延迟调用;如果没调用wait()或者get()函数,那么就不会执行线程入口函数
b)std::launch::async:立即创建一个子线程并执行,std::async默认使用std::launch::async标记。
1.1 将函数作为线程入口函数
#include<iostream>
#include<thread>
#include<future>
using namespace std;
int mythread()
{
cout<<"mythread() start "<<"threadid = "<<std::this_thread::get_id()<<endl;
std::chrono::milliseconds dura(5000);
std::this_thread::sleep_for(dura);
cout<<"mythread() end "<<"threadid = "<<std::this_thread::get_id()<<endl;
return 5;
}
int main()
{
cout<<"main"<<"thread_id = "<<std::this_thread::get_id()<<endl;
std::future<int> result = std::async(mythread);
cout<<"continue.....!"<<endl;
int def;
def = 0;
cout<<result.get()<<endl;
return 0;
}
- 主线程执行到result.get()时,会卡在这里,等待mythread执行完毕,拿到结果,才会继续执行下去。
- result.wait() 也会等待线程执行完毕,但不会返回结果,类似于join()
- result.get() 只能调用一次,不能调用多次,否者会报异常
1.2 将对象的成员函数作为线程入口函数
#include<iostream>
#include<thread>
#include<future>
using namespace std;
class A
{
public:
int mythread(int mypar)
{
cout << "mypar" << mypar << endl;
cout << "mythread() start " << "threadid = " << std::this_thread::get_id() << endl;
std::chrono::milliseconds dura(5000);
std::this_thread::sleep_for(dura);
cout << "mythread() end " << "threadid = " << std::this_thread::get_id() << endl;
return 5;
}
};
int main()
{
cout << "main" << "thread_id = " << std::this_thread::get_id() << endl;
A a;
int tmpar = 0;
std::future<int> result = std::async(&A::mythread,&a,tmpar);
cout << "continue.....!" << endl;
cout << result.get() << endl;
return 0;
}
1.3 std::launch作为参数传递到std::async
#include<iostream>
#include<thread>
#include<future>
using namespace std;
class A
{
public:
int mythread(int mypar)
{
cout << "mypar" << mypar << endl;
cout << "mythread() start " << "threadid = " << std::this_thread::get_id() << endl;
std::chrono::milliseconds dura(5000);
std::this_thread::sleep_for(dura);
cout << "mythread() end " << "threadid = " << std::this_thread::get_id() << endl;
return 5;
}
};
int main()
{
cout << "main" << "thread_id = " << std::this_thread::get_id() << endl;
A a;
int tmpar = 0;
std::future<int> result = std::async(std::launch::deferred,&A::mythread,&a,tmpar);
cout << "continue.....!" << endl;
return 0;
}
- 当使用std::launch::deferred时,若没有执行get()时,mythread线程都没有被创建出来,mythread()函数也没有被执行;若执行get(),发现子线程的id和主线程的id是一致的,没有创建出新线程,是在主线程中执行的mythread()函数。
二、std::packaged_task
- 打包任务,把任务包装起来
- 是个类模板,它的模板参数是各种可调用对象
- 通过std::packaged_task 来把各种可调用对象包装起来,方便作为将来的线程入口函数
#include<iostream>
#include<thread>
#include<future>
using namespace std;
int mythread(int mypar)
{
cout << "mypar" << mypar << endl;
cout << "mythread() start " << "threadid = " << std::this_thread::get_id() << endl;
std::chrono::milliseconds dura(5000);
std::this_thread::sleep_for(dura);
cout << "mythread() end " << "threadid = " << std::this_thread::get_id() << endl;
return 5;
}
int main()
{
cout << "main" << "thread_id = " << std::this_thread::get_id() << endl;
std::packaged_task<int(int)> mypt(mythread);
std::thread t1(std::ref(mypt), 1);
t1.join();
std::future<int> result = mypt.get_future();
cout <<result.get()<< endl;
cout << "main threadid = " << std::this_thread::get_id() << " end" << endl;
return 0;
}