本节内容需要包含头文件:#include <future>
①:启用async
看例子:
#include <iostream> #include <future> using namespace std; class A { public: int mythread(int data) { cout << data << endl; return data * 2; } }; int mythread() { cout << "mythread() start" << "threadid = " << std::this_thread::get_id() << endl; std::chrono::milliseconds dura(5000);//睡5秒 std::this_thread::sleep_for(dura); cout << "mythread() end" << "threadid = " << std::this_thread::get_id() << endl; return 5; } int main() { A a; int tmp = 12; cout << "main" << "threadid = " << std::this_thread::get_id() << endl; std::future<int> result1 = std::async(mythread); cout << "continue........" << endl; cout << result1.get() << endl; //卡在这里等待mythread()执行完毕,拿到结果 //类成员函数 std::future<int> result2 = std::async(&A::mythread, &a, tmp); //第二个参数是对象引用才能保证线程里执行的是同一个对象 //cout << result2.get() << endl;//get()只能调用一次,result2不再有结果值,转移的是存的数据类型,这里是int! //或者result2.wait(); cout << "finish all" << endl; return 0; }
②:std::async的第一个参数
#include <iostream> #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" << "threadid = " << std::this_thread::get_id() << endl; std::future<int> result1 = std::async(std::launch::deferred ,mythread); cout << "continue........" << endl; cout << result1.get() << endl; //卡在这里等待mythread()执行完毕,拿到结果 cout << "finish all" << endl; return 0; }
//可调用对象是普通函数 #include <thread> #include <iostream> #include <future> using namespace std; int mythread(int mypar) { cout << 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" << "threadid = " << std::this_thread::get_id() << endl; //我们把函数mythread通过packaged_task包装起来 //参数是一个int,返回值类型是int std::packaged_task<int(int)> mypt(mythread); std::thread t1(std::ref(mypt), 1);//传入真引用!不可以用detach模式 t1.join(); std::future<int> result = mypt.get_future(); //std::future对象里包含有线程入口函数的返回结果,这里result保存mythread返回的结果。 cout << result.get() << endl; return 0; }
//可调用对象是lambda表达式 int main() { cout << "main" << "threadid = " << std::this_thread::get_id() << endl; std::packaged_task<int(int)> mypt([](int mypar) { cout << 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; }); std::thread t1(std::ref(mypt), 1);//传真引用,因为是packege_task,mypt只能再被调用一次 t1.join(); std::future<int> result = mypt.get_future(); cout << result.get() << endl; cout << "finish overhead" << endl; return 0; }
//调用对象是lambda表达式,直接调用 int main() { cout << "main" << "threadid = " << std::this_thread::get_id() << endl; std::packaged_task<int(int)> mypt([](int mypar) { cout << 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; }); mypt(1);//也可以在主线程中直接调用,这样就和function的效果一样,但是只能调用一次 std::future<int> result = mypt.get_future(); cout << result.get() << endl; cout << "finish overhead" << endl; return 0; }
tip:了解ref
std::promise 类模板,我们能够在某个线程中给它赋值,然后我们可以在其他线程中把这个值取出来用;
总结:通过promise保存一个值,在将来某时刻我们通过把一个future绑定到这个promise上来得到这个绑定的值;
#include<iostream> #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); //定一个5秒的时间 std::this_thread::sleep_for(dura); //休息一定时常 int result = calc; //保存结果 tmpp.set_value(result); //####1.结果保存到了tmpp这个promise对象中 } void mythread2(std::future<int> &tmpf) { auto result = tmpf.get(); cout <<"mythread result = " << result<<endl; } int main() { std::promise<int> myprom; //声明一个std::promise对象myprom,保存的值类型为int; std::thread t1(mythread,std::ref(myprom),180); t1.join(); //获取结果值 std::future<int> fu1 = myprom.get_future();//####2.promise与future绑定,用于获取线程返回值 std::thread t2(mythread2,std::ref(fu1)); t2.join(); //等mythread2执行完毕 cout << "finish all" << endl; //fu1不再有用,已经为空;已经全部传入mythread2的tmpf中,但是myprom还存着值1810; return 0; } //对于ref,package_task、future都会移动后原本的变量就没有内容了,对于promise,却还有,要探索一下
延迟调用参数 std::launch::deferred【延迟调用】,std::launch::async【强制创建一个线程】;
std::async()我们一般不叫创建线程(他能够创建线程),我们一般叫它创建一个异步任务。std::async和std::thread最明显的不同:就是 async 有时候并不创建新线程。
①如果用std::launch::deferred 来调用async?
延迟到调用 get() 或者 wait() 时执行,如果不调用就不会执行
②如果用std::launch::async来调用async?
强制这个异步任务在新线程上执行,这意味着,系统必须要创建出新线程来运行入口函数。
③如果同时用 std::launch::async | std::launch::deferred
这里这个 | 意味着async的行为可能是 std::launch::async 创建新线程立即执行, 也可能是 std::launch::deferred 没有创建新线程并且延迟到调用get()执行,由系统根据实际情况来决定采取哪种方案
④不带额外参数 std::async(mythread),只给async 一个入口函数名,此时的系统给的默认值是 std::launch::async | std::launch::deferred 和 ③ 一样,有系统自行决定异步还是同步运行。
由于系统资源限制:
①如果用std::thread创建的线程太多,则可能创建失败,系统报告异常,崩溃。
②如果用std::async,一般就不会报异常,因为如果系统资源紧张,无法创建新线程的时候,async不加额外参数的调用方式就不会创建新线程。而是在后续调用get()请求结果时执行在这个调用get()的线程上。
如果你强制async一定要创建新线程就要使用 std::launch::async 标记。承受的代价是,系统资源紧张时可能崩溃。
③根据经验,一个程序中线程数量 不宜超过100~200 。
让系统自行决定是否创建线程:std::future<int> result = std::async(mythread);
问题焦点在于这个写法,任务到底有没有被推迟执行!
如何判断:通过future中wait_for()方法的返回值;详情看下一节内容
多阅读高手代码,多积累,提升自己技术!