#include<iostream> #include<string> #include<thread> #include<asyncinfo.h> #include<future> #include<vector> using namespace std; class A { public: int mythread2(int mypar) { cout << mypar << endl; cout << "mythred() start" << "thred id =" << std::this_thread::get_id() << endl;//打印新线程的ID std::chrono::milliseconds dura(5000);//定义一个5秒的时间 std::this_thread::sleep_for(dura);//休息了五秒 cout << "mythred() start" << "thred id =" << std::this_thread::get_id() << endl;//打印新线程的ID return 5; } }; int mythread() { cout << "mythred() start" << "thred id =" << std::this_thread::get_id() << endl;//打印新线程的ID std::chrono::milliseconds dura(5000);//定义一个5秒的时间 std::this_thread::sleep_for(dura);//休息了五秒 cout << "mythred() start" << "thred id =" << std::this_thread::get_id() << endl;//打印新线程的ID return 5; }
int mythread3(int mypar) { cout << mypar << endl; cout << "mythred() start" << "thred id =" << std::this_thread::get_id() << endl;//打印新线程的ID std::chrono::milliseconds dura(5000);//定义一个5秒的时间 std::this_thread::sleep_for(dura);//休息了五秒 cout << "mythred() start" << "thred id =" << std::this_thread::get_id() << endl;//打印新线程的ID return 5; }
//std::promise void mythread5(std::promise<int> &tmpp ,int calc) {//操作的变量为整形,返回的是int,运算结果是整型,所以是int //做一系列复杂运算。 calc++; calc *= 10; //做其他运算,花费了五秒。 std::chrono::milliseconds dura(5000);//定义一个5秒的时间 std::this_thread::sleep_for(dura);//休息了五秒 int result = calc;//保存结果 tmpp.set_value(result);//结果我保存到了tmpp这个对象中 return; } //创建一个新线程,用上面线程的值 void mythread6(std::future<int> &tmpp) { auto result = tmpp.get(); cout << result << endl; return;
} int main() { /* (1)std::async、std::future创建后台任务并返回 * 希望线程返回一个结果 * std::async是一个函数模板,用来启动一个异步任务,启动后,返回一个std::future对象,这是一个类模板 * 什么叫“启动一个异步任务”,就是自动创建一个线程,并开始执行对应的线程入口函数,他返回一个std::future对象 * 这个对象里面就含有这个线程入口函数所返回的结果(线程返回的结果),我们可以通过调用这个future对象的成员函数get()来获取结果。 * “future”将来的意思,有人也称呼std::future提供了一种访问异步操作结果的机制,就是说这个结果你可能没有办法马上拿到,但是不久的将来 * (线程执行完毕)的时候,你就能拿到结果了,所以大家就这么理解:这个future里会保存一个值。在将来的某个时刻能够拿到 我们通过额外向std::async()传递一个参数,该参数的类型是std::lunnch类型(枚举类型),来达到一些特殊的目的。 a)std::launch::deferred;表示线程入口函数调用被延迟到std::future的wait()或者get()函数调用时才执行。 问题:那如果wait()或者get()没有执行,这个线程会执行吗? 答案:线程根本就没创建,所以也没执行。 std::launch::deferred;延迟调用,并且没有创建新线程,是在主线程中调用的线程入口函数; b)std::launch::async,在调用async函数的时候就开始创建线程。 async()函数默认的用的是std::launch::async | std::launch::deferred 系统会根据自己需求选择二者其一。 经过package_task或者std::promise打包后用get_future()获得future对象,后面还需要用get得到该对象保存的值。如果没有打包,原生的future类对象则直接用get获得值 * (2)std::package_task :打包任务,把任务包装起来 * 是个类模板,它的模板参数是各种可调用对象(函数,类中圆括号重载,类对象),通过std::package_task将各种可调用对象包装起来,方便作为线程入口函数来调用。 * package_task包装起来的可调用对象还可以直接调用,所以从这个角度讲,package_task,也是一个可调用对象。 (3)std::promise 类模板,作用:我们在某个线程中给他赋值,在其他线程中把这个值取出来使用。 通过promise保存一个值,在将来某个时刻我们通过吧一个future绑定到这个promise上来得到这个绑定的值 * (4)小结 :到底怎么用,什么时候用 * 我们学这些东西的目的,并不是把他们都用在实际开发中, * 相反,如果咱们能够用最少的东西写出稳定高效的多线程程序,更值得赞赏; * 我们为了成长,必须要阅读一些高手的代码,从而加速实现自己代码的积累,我们的技术就会有大幅度的提升。 * */
//下列程序通过std::future对象的get()成员函数等待线程执行结束并返回结果。 //这个get函数很牛,不拿到将来的返回值誓不罢休,不拿到值我就卡在这里等待拿值。 A a; cout << "main" << " thread is " << std::this_thread::get_id() << endl; //std::future<int> result = std::async(mythread);//创建一个线程并开始执行。绑定关系,如果线程入口函数有参数,那么从第二个参数开始给参数的值 //通过系统的async创建一个异步任务,也就是开启一个新线程,线程入口函数为mythread //std::future<int> resule = std::async(&A::mythread2,&a,12);//第一个参数为成员函数的地址,第二个为对象引用,才能保证线程里边用的是同一个对象。,从第三个开始给参数的地址。 //std::future<int> result = std::async(std::launch::deferred, mythread);//系统延迟执行,如果不调用get不执行。 std::future<int> result = std::async(std::launch::async, mythread);//系统默认标记,不需要等get或者wait就可以创建线程并且执行。
cout << "continue.....!" << endl; int def; cout << result.get();//卡在这里等待mythread()执行完毕,拿到结果。 // result.get();//不能调用多次,调用多次就报异常,只能调用一次 result.wait();//只是等待,不接收返回值。类似于join
//std::pacckage_task cout << "main" << "thread id =" << std::this_thread::get_id() << endl; std::packaged_task<int(int)> mypt(mythread);//我们把函数mythread通过package_task包装起来 std::thread t1(std::ref(mypt),1);//ref纯引用,防止复制,1为线程入口函数的参数,线程直接开始执行。 t1.join();//等待线程执行完毕 std::future<int> result1 = mypt.get_future();//std::future对象里包含有线程入口函数的返回结果,这里result保存muthread返回的结果。 cout << result1.get() << endl;
//可以包装lambda表达式 std::packaged_task<int(int)> mypt2([](int mypar) {//第一个int为返回类型为整形,第二个int为参数为整形,将这种函数包装到package_task里面去。 cout << mypar << endl; cout << "mythred() start" << "thred id =" << std::this_thread::get_id() << endl;//打印新线程的ID std::chrono::milliseconds dura(5000);//定义一个5秒的时间 std::this_thread::sleep_for(dura);//休息了五秒 cout << "mythred() start" << "thred id =" << std::this_thread::get_id() << endl;//打印新线程的ID return 5; }); //调用package_task ,没有创建线程,相当于函数调用。 //mypt2(105); //std::future<int> result =mypt2.getfuture(); //cout<<result.get()<<endl;
vector<std::packaged_task<int(int)>> mypt4; mypt4.push_back(std::move(mypt2));//容器,这里mypt2为空了。
std::packaged_task<int(int)> mypt5; auto itor = mypt4.begin(); mypt5 = std::move(*itor);//换一个位置。 mypt4.erase(itor);//删除第一个元素,迭代已经失效了,所以后续代码不可以再使用itor mypt5(102); std::future<int> result1 = mypt5.get_future(); cout << result1.get();
//std::promise std::promise<int> myprom;//声明一个std::promise对象myprom,保存的值类型为int; std::thread ti(mythread5, std::ref(myprom), 180); ti.join(); //获取结果值 std::future<int> ful = myprom.get_future();//promise和future绑定,用于获取线程返回值。 auto resultt = ful.get();//会立即拿到。 cout << "result=" << resultt << endl;
//让另一个线程用上面这个代码的线程所返回的值 std::thread myproo(mythread6, std::ref(ful)); myproo.join();//等待myproo线程执行完毕
}