一、std::async / std::future创建后台任务并返回值
- 希望线程返回一个结果
- std::async 是个函数模板,用来启动一个异步任务,启动一个异步任务之后,返回一个std::future对象,std::future是一个类模板
什么叫“启动一个异步任务”
- 就是自动创建一个线程并开始执行对应的入口函数,它返回一个std::future对象
- 这个std::future对象里面就含有函数返回的结果(线程返回的结果),我们可以通过调用future对象的成员函数get()来获取结果
- 有人也称呼std::future提供了一种访问异步操作结果的机制,就是说这个结果你可能没有办法马上拿到,但不久的将来,你就能够拿到结果了,所以大家都这么理解:这个future(对象)里会保存一个值
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <string>
#include <list>
#include <thread>
#include <mutex>
#include <future>
using namespace std;
int MyThread()
{
std::cout << "MyThread Start thread_id = " << std::this_thread::get_id() << std::endl;
std::chrono::milliseconds dura(5000);
std::this_thread::sleep_for(dura);
std::cout << "MyThread End thread_id = " << std::this_thread::get_id() << std::endl;
return 5;
}
int main(int argc, char* argv[])
{
//下列程序通过std::future对象的get()成员函数,等待线程MyThread执行结束并返回结果
//这个get()函数很牛,不拿到将来的返回值 誓不罢休,不拿到值我就卡在这里等待拿值
std::cout << "main thread_id = " << std::this_thread::get_id() << std::endl;
//创建一个线程,并开始执行,绑定关系
//流程并不会卡在这里
std::future<int> result = std::async(MyThread);
std::cout << "continue....." << std::endl;
std::cout << result.get() << std::endl;//卡在这里等待MyThread执行完毕,拿到结果
//get()只能调用一次,不能调用多次,否则会报异常
//result.wait() //等待线程返回,本身并不返回结果
std::cout << "main end thread_id = " << std::this_thread::get_id() << std::endl;
system("pause");
return 0;
}
1.1类中调用线程入口函数
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <string>
#include <list>
#include <thread>
#include <mutex>
#include <future>
using namespace std;
class A
{
public:
int MyThread(int my_par)
{
std::cout << "my_par = " << my_par << std::endl;
std::cout << "MyThread Start thread_id = " << std::this_thread::get_id() << std::endl;
std::chrono::milliseconds dura(5000);
std::this_thread::sleep_for(dura);
std::cout << "MyThread End thread_id = " << std::this_thread::get_id() << std::endl;
return 5;
}
protected:
private:
};
int main(int argc, char* argv[])
{
//下列程序通过std::future对象的get()成员函数,等待线程MyThread执行结束并返回结果
//这个get()函数很牛,不拿到将来的返回值 誓不罢休,不拿到值我就卡在这里等待拿值
A my_obj_a;
int tmp_par = 12;
std::cout << "main thread_id = " << std::this_thread::get_id() << std::endl;
//第2个参数是对象引用,才能保证线程里用的是同一个对象
std::future<int> result = std::async(&A::MyThread, &my_obj_a, tmp_par);
std::cout << "continue....." << std::endl;
std::cout << result.get() << std::endl;//卡在这里等待MyThread执行完毕,拿到结果
//get()只能调用一次,不能调用多次,否则会报异常
//result.wait() //等待线程返回,本身并不返回结果
std::cout << "main end thread_id = " << std::this_thread::get_id() << std::endl;
system("pause");
return 0;
}
1.2 std::async()传入参数
1.2.1 std::launch::async(),在调用的时候就开始创建线程
async()函数,默认用的就是std::launch::async | std::launch::thread标记
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <string>
#include <list>
#include <thread>
#include <mutex>
#include <future>
using namespace std;
class A
{
public:
int MyThread(int my_par)
{
std::cout << "my_par = " << my_par << std::endl;
std::cout << "MyThread Start thread_id = " << std::this_thread::get_id() << std::endl;
std::chrono::milliseconds dura(5000);
std::this_thread::sleep_for(dura);
std::cout << "MyThread End thread_id = " << std::this_thread::get_id() << std::endl;
return 5;
}
protected:
private:
};
int main(int argc, char* argv[])
{
//下列程序通过std::future对象的get()成员函数,等待线程MyThread执行结束并返回结果
//这个get()函数很牛,不拿到将来的返回值 誓不罢休,不拿到值我就卡在这里等待拿值
A my_obj_a;
int tmp_par = 12;
std::cout << "main thread_id = " << std::this_thread::get_id() << std::endl;
//第2个参数是对象引用,才能保证线程里用的是同一个对象
//std::future<int> result = std::async(&A::MyThread, &my_obj_a, tmp_par);
std::future<int> result = std::async(std::launch::async, &A::MyThread, &my_obj_a, tmp_par);
std::cout << "continue....." << std::endl;
std::cout << result.get() << std::endl;//卡在这里等待MyThread执行完毕,拿到结果
//get()只能调用一次,不能调用多次,否则会报异常
//result.wait() //等待线程返回,本身并不返回结果
std::cout << "main end thread_id = " << std::this_thread::get_id() << std::endl;
system("pause");
return 0;
}
1.2.2 std::launch::defered
表示线程入口函数调用延迟到std::future的wait()或者get()函数调用时才执行
如果wait()或者get()函数没有被调用,那么线程实际上根本没有被创建
std::launch::defered延迟调用,并且没有创建新线程,是在主线程中调用的线程入口函数
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <string>
#include <list>
#include <thread>
#include <mutex>
#include <future>
using namespace std;
class A
{
public:
int MyThread(int my_par)
{
std::cout << "my_par = " << my_par << std::endl;
std::cout << "MyThread Start thread_id = " << std::this_thread::get_id() << std::endl;
std::chrono::milliseconds dura(5000);
std::this_thread::sleep_for(dura);
std::cout << "MyThread End thread_id = " << std::this_thread::get_id() << std::endl;
return 5;
}
protected:
private:
};
int main(int argc, char* argv[])
{
//下列程序通过std::future对象的get()成员函数,等待线程MyThread执行结束并返回结果
//这个get()函数很牛,不拿到将来的返回值 誓不罢休,不拿到值我就卡在这里等待拿值
A my_obj_a;
int tmp_par = 12;
std::cout << "main thread_id = " << std::this_thread::get_id() << std::endl;
std::future<int> result = std::async(std::launch::deferred, &A::MyThread, &my_obj_a, tmp_par);
std::cout << "continue....." << std::endl;
std::cout << result.get() << std::endl;//卡在这里等待MyThread执行完毕,拿到结果
//get()只能调用一次,不能调用多次,否则会报异常
//result.wait() //等待线程返回,本身并不返回结果
std::cout << "main end thread_id = " << std::this_thread::get_id() << std::endl;
system("pause");
return 0;
}
二、std::packged_task 打包任务,把任务打包起来
是个类模板,它的模板参数是各种可调用对象,通过std::packged_task 来把各种可调用对象包装起来,方便将来作为线程入口函数
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <string>
#include <list>
#include <thread>
#include <mutex>
#include <future>
using namespace std;
int MyThread(int my_par)
{
std::cout << "my_par = " << my_par << std::endl;
std::cout << "MyThread Start thread_id = " << std::this_thread::get_id() << std::endl;
std::chrono::milliseconds dura(5000);
std::this_thread::sleep_for(dura);
std::cout << "MyThread End thread_id = " << std::this_thread::get_id() << std::endl;
return 5;
}
int main(int argc, char* argv[])
{
std::cout << "main thread_id = " << std::this_thread::get_id() << std::endl;
std::packaged_task<int(int)> mypt(MyThread);//把MyThrea()函数通过packge_task包装起来
std::thread t1(std::ref(mypt), 1); //线程直接开始执行,第2个参数 作为线程入口函数的参数
t1.join();
//std::future对象里包含有线程入口函数的返回结果,这里result保存MyThread的返回值
std::future<int> result = mypt.get_future();
std::cout << result.get() << std::endl;
std::cout << "I love China" << std::endl;
system("pause");
return 0;
}
包装一个lambda表达式
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <string>
#include <list>
#include <thread>
#include <mutex>
#include <future>
using namespace std;
int main(int argc, char* argv[])
{
std::cout << "main thread_id = " << std::this_thread::get_id() << std::endl;
//packaged_task包装起来的可调用对象还可以直接调用,所以从这个角度来讲,packaged_task对象也是一个可调用对象
std::packaged_task<int(int)> mypt([](int my_par){
std::cout << "my_par = " << my_par << std::endl;
std::cout << "MyThread Start thread_id = " << std::this_thread::get_id() << std::endl;
std::chrono::milliseconds dura(5000);
std::this_thread::sleep_for(dura);
std::cout << "MyThread End thread_id = " << std::this_thread::get_id() << std::endl;
return 5;
});
std::thread t1(std::ref(mypt), 1); //线程直接开始执行,第2个参数 作为线程入口函数的参数
t1.join();
//std::future对象里包含有线程入口函数的返回结果,这里result保存MyThread的返回值
std::future<int> result = mypt.get_future();
std::cout << result.get() << std::endl;
std::cout << "I love China" << std::endl;
system("pause");
return 0;
}```
直接调用,相当于函数调用
```cpp
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <string>
#include <list>
#include <thread>
#include <mutex>
#include <future>
using namespace std;
int main(int argc, char* argv[])
{
std::cout << "main thread_id = " << std::this_thread::get_id() << std::endl;
//packaged_task包装起来的可调用对象还可以直接调用,所以从这个角度来讲,packaged_task对象也是一个可调用对象
std::packaged_task<int(int)> mypt([](int my_par){
std::cout << "my_par = " << my_par << std::endl;
std::cout << "MyThread Start thread_id = " << std::this_thread::get_id() << std::endl;
std::chrono::milliseconds dura(5000);
std::this_thread::sleep_for(dura);
std::cout << "MyThread End thread_id = " << std::this_thread::get_id() << std::endl;
return 5;
});
mypt(105);//直接调用,相当于函数调用
std::future<int> result = mypt.get_future();
std::cout << result.get() << std::endl;
system("pause");
return 0;
}
三、std::promise 类模板
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <string>
#include <list>
#include <thread>
#include <mutex>
#include <future>
using namespace std;
void MyThread(std::promise<int> &tmpp, int calc)
{
//做一系列复杂的动作
calc++;
calc *= 10;
//做其他运算,比如整整花费了5秒钟
std::chrono::milliseconds dura(5000);
std::this_thread::sleep_for(dura);
//终于计算出来结果了
int result = calc;
tmpp.set_value(result);//结果保存在tmpp这个对象中
return;
}
int main(int argc, char* argv[])
{
std::cout << "main thread_id = " << std::this_thread::get_id() << std::endl;
//通过promise保存一个值,在将来某个时刻我们通过把一个future绑定到这个promise上来得到这个绑定的值
std::promise<int> my_prom;//声明一个std::promise对象,保存的值类型为int
std::thread t1(MyThread, std::ref(my_prom), 180);
t1.join();
//获取结果值
std::future<int> fu1 = my_prom.get_future();//promise和future绑定,用于获取线程返回值
auto result = fu1.get();
std::cout << "result = " << result << std::endl;
std::cout << "I Love China!" << std::endl;
system("pause");
return 0;
}
两个线程
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <string>
#include <list>
#include <thread>
#include <mutex>
#include <future>
using namespace std;
void MyThread(std::promise<int> &tmpp, int calc)
{
//做一系列复杂的动作
calc++;
calc *= 10;
//做其他运算,比如整整花费了5秒钟
std::chrono::milliseconds dura(5000);
std::this_thread::sleep_for(dura);
//终于计算出来结果了
int result = calc;
tmpp.set_value(result);//结果保存在tmpp这个对象中
return;
}
void MyThread2(std::future<int> &tmpf)
{
auto result = tmpf.get();
std::cout << "MyThread2 result = " << result << std::endl;
return;
}
int main(int argc, char* argv[])
{
std::cout << "main thread_id = " << std::this_thread::get_id() << std::endl;
//通过promise保存一个值,在将来某个时刻我们通过把一个future绑定到这个promise上来得到这个绑定的值
std::promise<int> my_prom;//声明一个std::promise对象,保存的值类型为int
std::thread t1(MyThread, std::ref(my_prom), 180);
t1.join();
//获取结果值
std::future<int> fu1 = my_prom.get_future();//promise和future绑定,用于获取线程返回值
std::thread t2(MyThread2, std::ref(fu1));
t2.join();//等待MyThread2线程执行完毕
std::cout << "I Love China!" << std::endl;
system("pause");
return 0;
}