一:std::async和std::future创建后台任务并返回值
希望线程返回一个结果;
std::async是个函数模板,用来启动一个异步任务,启动起来一个异步任务之后,返回一个std::future对象,std::future是个类模板。
什么叫“启动一个异步任务”,就是自动创建一个线程并开始执行对应的线程入口函数,返回一个std::future对象。
这个std::future对象里边就含有线程入口函数所返回的结果(线程返回的结果);可以通过调用future对象的成员函数get()来获取结果。
“future”:将来的意思,也称呼std::future提供了一种访问异步操作结果的机制,就是说,这个结果没有办法马上拿到,在线程执行完毕的时候,就能够拿到结果了。
future的终极理解:这个future(对象)里会保存一个值,在将来的某个时刻能够拿到。
下列程序通过std::future对象的get()成员函数等待线程执行结束并返回结果。
这个get()函数很牛,不拿到将来的返回值誓不罢休,不拿到值就等待,直到拿到值为止。
int mythread() //线程入口函数
{
cout << "mythread() start" << " threadId = " << std::this_thread::get_id() << endl; //打印新线程id
std::chrono::milliseconds dura(5000); //定义一个5秒时间
std::this_thread::sleep_for(dura); //休息了一定时长
cout << "mythread() end" << " threadId = " << std::this_thread::get_id() << endl; //打印新线程id
return 5;
}
int main()
{
cout << "main threadId = " << std::this_thread::get_id() << endl;
std::future result = std::async(mythread); //创建一个线程开始执行,绑定关系;流程并不卡到这里
cout << "contine....!" << endl;
int def;
def = 0;
cout << "def = 0" << endl;
cout << result.get() << endl; //卡在这里等待mythread()执行完毕,拿到结果。
//cout << result.get() << endl; //get()只能调用一次
//result.wait(); //等待线程返回,本身不返回结果。有点类似.join();
cout << "main主函数执行结束" << endl; //最后执行这句,整个进程退出
return 0;
}
通过额外向std::async()传递一个参数,该参数类型是std::launch类型(枚举类型);来表达一些特殊的目的;
1>std::launch::deferred:表示线程入口函数调用被延迟到std::future的wait()或者get()函数调用时才执行。
如果wait或者get()没有被调用,那么线程会执行吗?
实际上线程根本就没有创建,更不会执行;
std::launch::deferred:延迟调用,并且没有创建新线程,是在主线程中调用的线程入口函数;
2>std::launch::async,在调用async函数的时候就开始创建线程。
async()函数,默认使用的就是std::launch::async
class A
{
public:
int mythread(int mypar) //线程入口函数
{
cout << mypar << endl;
cout << "mythread() start" << " threadId = " << std::this_thread::get_id() << endl; //打印新线程id
std::chrono::milliseconds dura(5000); //定义一个5秒时间
std::this_thread::sleep_for(dura); //休息了一定时长
cout << "mythread() end" << " threadId = " << std::this_thread::get_id() << endl;//打印新线程id
return 5;
}
};
int main()
{
A a;
int temper = 12;
cout << "main threadId = " << std::this_thread::get_id() << endl;
//std::future result = std::async(mythread, temper); //创建一个线程开始执行,绑定关系;流程并不卡到这里
std::futureresult = std::async(std::launch::async, &A::mythread, &a, temper); //第二个参数是对象引用,才能保证线程里面用的是同一个对象。
cout << "contine....!" << endl;
int def;
def = 0;
cout << "def = 0" << endl;
cout << result.get() << endl; //卡在这里等待mythread()执行完毕,拿到结果。
//cout << result.get() << endl; //get()只能调用一次
//result.wait(); //等待线程返回,本身不返回结果。有点类似.join();
cout << "main主函数执行结束" << endl; //最后执行这句,整个进程退出
return 0;
}
二:std::packaged_task
打包任务,把任务包装起来。是个类模板,它的模板参数是各种可调用对象;通过 packaged_task 来把各种可调用对象包装起来,方便将来作为线程入口函数来调用。
packaged_task 包装起来的可调用对象还可以直接调用,所以,从这个角度来讲,packaged_task对象,也是一个可调用对象。
int mythread(int mypar) //线程入口函数
{
cout << mypar << endl;
cout << "mythread() start" << " threadId = " << std::this_thread::get_id() << endl; //打印新线程id
std::chrono::milliseconds dura(5000); //定义一个5秒时间
std::this_thread::sleep_for(dura); //休息了一定时长
cout << "mythread() end" << " threadId = " << std::this_thread::get_id() << endl;//打印新线程id
return 5;
}
int main()
{
cout << "main threadId = " << std::this_thread::get_id() << endl;
std::packaged_task mypt(mythread); //把函数mythread通过packaged_task包装起来
//packaged_task 第一个int是函数返回类型,第二个是参数类型
std::thread t1(std::ref(mypt), 3); //线程直接开始执行,第二个参数作为线程入口函数的参数。
t1.join(); //等待线程执行完毕。
std::future result = mypt.get_future();
//std::future对象里包含有线程入口函数的返回结果,这里result保存mythread返回的结果。
cout << result.get() << endl;
cout << "main主函数执行结束" << endl; //最后执行这句,整个进程退出
return 0;
}
另一种写法
int main()
{
cout << "main threadId = " << std::this_thread::get_id() << endl;
std::packaged_task mypt([](int mypar) {
cout << mypar << endl;
cout << "mythread() start" << " threadId = " << std::this_thread::get_id() << endl; //打印新线程id
std::chrono::milliseconds dura(5000); //定义一个5秒时间
std::this_thread::sleep_for(dura); //休息了一定时长
cout << "mythread() end" << " threadId = " << std::this_thread::get_id() << endl;//打印新线程id
return 5;
});
std::thread t1(std::ref(mypt), 3); //线程直接开始执行,第二个参数作为线程入口函数的参数。
t1.join(); //等待线程执行完毕。
std::future result = mypt.get_future();
//std::future对象里包含有线程入口函数的返回结果,这里result保存mythread返回的结果。
cout << result.get() << endl;
cout << "main主函数执行结束" << endl; //最后执行这句,整个进程退出
return 0;
}
另另一种写法,packaged_task包装起来的可调用对象还可以直接调用,packaged_task对象是一个可调用对象,没有创建新的线程。
int main()
{
cout << "main threadId = " << std::this_thread::get_id() << endl;
std::packaged_task mypt([](int mypar) {
cout << mypar << endl;
cout << "mythread() start" << " threadId = " << std::this_thread::get_id() << endl; //打印新线程id
std::chrono::milliseconds dura(5000); //定义一个5秒时间
std::this_thread::sleep_for(dura); //休息了一定时长
cout << "mythread() end" << " threadId = " << std::this_thread::get_id() << endl;//打印新线程id
return 5;
});
mypt(105); //直接调用,相当于函数调用,没有创建新的线程
std::future result = mypt.get_future();
cout << result.get() << endl;
cout << "main主函数执行结束" << endl; //最后执行这句,整个进程退出
return 0;
}
另另另一种写法
vector > mytasks; //容器
int main()
{
cout << "main threadId = " << std::this_thread::get_id() << endl;
std::packaged_task mypt([](int mypar) {
cout << mypar << endl;
cout << "mythread() start" << " threadId = " << std::this_thread::get_id() << endl; //打印新线程id
std::chrono::milliseconds dura(5000); //定义一个5秒时间
std::this_thread::sleep_for(dura); //休息了一定时长
cout << "mythread() end" << " threadId = " << std::this_thread::get_id() << endl;//打印新线程id
return 5;
});
mytasks.push_back(std::move(mypt)); //入容器,这里用了移动语义,入进去之后mypt就为空。
std::packaged_task mypt2; //用来接收mypt
auto iter = mytasks.begin();
mypt2 = std::move(*iter); //移动语义
mytasks.erase(iter); //删除第一个元素,迭代器已经失效了,所以后续代码不可以再使用iter。
mypt2(123);
std::future result = mypt2.get_future();
cout << result.get() << endl;
cout << "main主函数执行结束" << endl; //最后执行这句,整个进程退出
return 0;
}
三:std::promise
类模板。能够在某个线程中给它赋值,然后可以在其他线程中,把这个值取出来使用;
总结:通过promise保存一个值,在将来某个时刻我们通过把一个future绑定到这个promise上来得到这个绑定的值。
std::promise myprom; //声明一个std::promise对象myporm,保存的值类型为int;