一、async
std::future是一个类模板
std::async 是一个函数模板
作用:启动一个异步任务,启动起来之后返回一个std::future对象
什么是“启动一个异步任务‘?
自动创建一个线程并且开始执行对应的线程入口函数,它返回一个std::future对象,这个对象里面就包含线程入口函数所返回的接口(线程返回的结果),可以通过调用future对象的成员函数get函数来获取。
#include <iostream>
#include <thread>
#include <future>
#include <chrono>
int myThread()
{
std::cout << "myThread() start" << "\tthread ID ="
<< std::this_thread::get_id() << std::endl;
std::this_thread::sleep_for(std::chrono::seconds(5));
std::cout << "end" << "\t thread ID" << std::this_thread::get_id() << std::endl;
return 10;
}
int main()
{
std::cout << "main" << "\tthread ID =" << std::this_thread::get_id() << std::endl;
std::future<int> result = std::async(myThread);
std::cout << "continue......" << std::endl;
int def = 0;
std::cout << "myThread =" << result.get() << std::endl;
//future在未获取到线程的返回值的时候,调用future函数的get()函数的时候,会阻塞在本行
//直到future获取到线程的返回值的时候,get()函数才会返回结果,程序继续执行
std::cout << "I love China" << std::endl;
return 0;
}
future类的成员函数get()只有在future得到线程的返回值的时候,get()函数才会返回,否则则会阻塞在当前的位置上,并且注意,get()函数只能调用一次。
future类的成员函数wait()函数会阻塞当前的进程,直到future得到线程的返回值,有点类似于join();
对于async创建线程于thread相同,如果需要调用类的成员函数
std::future<int> result = std::async(&A::myThread,std::ref(myOBJ),temp);
第一个参数为函数的地址,第二个参数为类的对象,后面的就是函数的参数
1.1我们可以给async传递一个额外的参数,该参数的类型是std::launch类型,来进行不同的操作
std::launch是一个枚举
1.1.1std::launch::deferred:表示线程入口函数调用延迟到std::future的wait函数或者get函数被调用才会执行线程函数。
#include <iostream>
#include <thread>
#include <future>
#include <chrono>
class A
{
public:
int myThread(int temp)
{
std::cout << "myThread() start" << "\tthread ID ="
<< std::this_thread::get_id() << std::endl;
std::cout << "temp = " << temp << std::endl;
std::this_thread::sleep_for(std::chrono::seconds(5));
std::cout << "end" << "\t thread ID" << std::this_thread::get_id() << std::endl;
return 10;
}
};
int main()
{
A myOBJ;
int temp = 12;
std::cout << "main" << "\tthread ID =" << std::this_thread::get_id() << std::endl;
std::future<int> result = std::async(std::launch::deferred,&A::myThread,std::ref(myOBJ),temp);
std::cout << "continue......" << std::endl;
std::cout << "I love China" << std::endl;
return 0;
}
当给async加上额外的参数std::launch::defferred的时候在不调用wait或者get函数的时候,这个线程并不会被创建。
在调用wait函数的时候
我们可以发现子线程的ID竟然于主线程的ID相同,说明并没有子线程调用,说明延迟调用并没有创建新的线程,而是在主线程中进行的。
1.1.2std::launch::async,表示在调用async的时候就开始创建线程
std::future<int> result = std::async(std::launch::async,&A::myThread,std::ref(myOBJ),temp);
可以看到现在确实创建了一个新的线程。不需要调用wait或者get函数才创建线程。std::async函数的默认值就是std::launch::async。
二、std::packaged_task
是一个类模板,他的模板参数是各种可调用参数,通过std::packaged_ task来把各种可调用对象包装起来,方便将来作为线程入口
#include <iostream>
#include <thread>
#include <future>
int myThread(int temp)
{
std::cout << "myThread() start" << "\tthread ID ="
<< std::this_thread::get_id() << std::endl;
std::cout << "temp = " << temp << std::endl;
std::this_thread::sleep_for(std::chrono::seconds(5));
std::cout << "end" << "\t thread ID = " << std::this_thread::get_id() << std::endl;
return 10;
}
int main()
{
std::cout << "main" << "\tthread ID =" << std::this_thread::get_id() << std::endl;
std::packaged_task<int(int)>myPT1(myThread); //相当于myThread通过packaged_task包装
std::thread myThread1(std::ref(myPT1), 1); //创建新的线程
myThread1.join();
std::future<int> result = myPT1.get_future();
std::cout << "future = " << result.get() << std::endl;
std::packaged_task<int(int)>myPT2([](int var) {
std::cout << "var =" << var << std::endl;
std::cout << "Thread() start" << "\tthread ID ="
<< std::this_thread::get_id() << std::endl;
return 5;
});
myPT2(100); //相当于直接调用函数,并没有创建线程
result = myPT2.get_future();
std::cout << "future = " << result.get() << std::endl;
return 0;
}
可以看到通过thread创建了新的线程,直接调用就相当于调用函数,是在主线程中进行的。
std::cout << "main" << "\tthread ID =" << std::this_thread::get_id() << std::endl;
std::packaged_task<int(int)>myPT1(myThread);
std::vector<std::packaged_task<int(int)>> myPackVec;
myPackVec.push_back(std::move(myPT1));
auto iter = myPackVec.begin();
std::packaged_task<int(int)>myPT2;
myPT2 = std::move(*iter);
myPackVec.erase(iter); //此时需要即使的删除,move并没有对容器本身操作,内部size任为1,但是包含的内容已经失效
myPT2(15);
std::future<int>result = myPT2.get_future();
std::cout << "future =" << result.get() << std::endl;
通过容器对packaged_task进行操作时,需要使用std::move来进行操作。
三、std::promise
是一个类模板
作用:可以在某一个线程中给他赋值,然后我们可以再在其他线程中,把这个值取出来
#include <iostream>
#include <thread>
#include <future>
#include <chrono>
void myThread1(std::promise<int> &myProm, int calc)
{
calc += 10;
std::this_thread::sleep_for(std::chrono::seconds(2));
myProm.set_value(calc);
return;
}
void myThread2(std::future<int>& temp)
{
std::cout << "temp.get() =" << temp.get() << std::endl;
return;
}
int main()
{
std::promise<int> myPromise;
std::future<int> result = myPromise.get_future();
std::thread t1(myThread1, std::ref(myPromise), 100);
t1.join();
std::thread t2(myThread2, std::ref(result));
t2.join();
std::cout << "main end" << std::endl;
return 0;
}