文章目录
一,async函数与future对象的使用
1,async的普遍用法
std::async是一个函数模板,用来启动一个异步任务,启动起来一个异步任务之后,它返回一个std::future对象,这个对象是个类模板。
什么叫“启动一个异步任务”?就是自动创建一个线程,并开始 执行对应的线程入口函数,它返回一个std::future对象,这个std::future对象中就含有线程入口函数所返回的结果,我们可以通过调用future对象的成员函数get()来获取结果。下面给出一个使用例子,并且在后文解释这个程序。
注意要带头文件#include<future>
#include <iostream>
#include <thread>
#include<future>
using namespace std;
//该代码让out线程中的unique_lock使用try_to_lock参数尝试拿锁
int mythread(int a)
{
cout << "mythread() start" << "threadid = " << std::this_thread::get_id() << endl;
std::chrono::milliseconds dura(3000);//休眠3秒
std::this_thread::sleep_for(dura);
cout << "mythread() end" << "threadid = " << std::this_thread::get_id() << endl;
return 5;
}
int main()
{
std::future<int> result = std::async(mythread,1);
int answer=result.get();
cout << "线程返回值是" << answer << endl;
return 0;
}
1,在我们以前用thread类创建线程的时候,一般是不方便得到线程的返回值的,除非我们将返回值赋予一个全局变量,但这毕竟不太方便。而async就实现了返回线程的返回值这个功能,用一个future对象去接。接到的future对象以后再通过get()方法就可以得到线程函数的返回值。有了这个功能我们就可以模拟函数调用过程中用一个局部对象接返回值的功能,同时该功能是多线程的。
2,在这个程序中,std::future<int> result = std::async(mythread,1);
这条语句调用了mythread入口函数开始运行线程。和thread mythobj(mythread);
类似,都是新创建一个线程,不过async方法可以有future对象接返回值。而future对象的.get()方法调用,和mythobj.join()
类似,都是等待子线程返回,区别是future对象的.get()方法会得到子线程的返回值。另外,该async函数的使用方法其实还有一个同学们容易忽略的地方,这个在后文会讲解。
注意:
1,除了future的.get()方法,还可以使用future的.wait()方法等待子线程返回,不过.wait()方法不会返回线程函数返回值。
2,.get()或者.wait()方法只能调用一次。就像thread中的.join()只能调用一次一样
2,async的可选参数
前面使用async函数模板的一条语句为std::future<int> result = std::async(mythread,1);
,实际上async函数模板还可以传递std::launch类型(枚举类型)的参数,来达到一些特殊的目的。
2.1 std::launch::async参数
1,该参数加入以后的写法为std::future<int> result = std::async(std::launch::async ,mythread,1);
该参数表示:mythread这个异步任务在新线程上执行,到future对象的.get()方法或者.wait()方法上返回主线程。
2,看完1的介绍,读者应该想到加了launch::async
参数的async函数的作用和默认不加参数的作用好像是一样的,事实上同学们经过试验发现的确如此。不过,前文我也说过,不加参数的async函数还有一个容易忽略的点,这个容易忽略的点其实就是其和加了launch::async
参数的一个区别。这个点在我接下来介绍了std::launch::deferred
以后就能理解了,下面先介绍std::launch::deferred
参数。
2.2 std::launch::deferred参数
1,该参数加入以后的写法为std::future<int> result = std::async(std::launch::deferred ,mythread,1);
,这条语句中,async函数换了launch::deferred参数,表示mythread方法暂时不执行,而是等到调用future对象的.get()方法或者.wait()方法以后,在主线程中继续执行。注意:这里没有新开一个线程。
2.3 std::launch::async|std::launch::deferred参数
前面留下的要介绍的关于async函数模板不加参数时容易忽略的点现在终于可以讲了:
1,实际上async函数模板不加参数时,第一个参数默认就是std::launch::async|std::launch::deferred。该参数表示如果系统资源足够的话就使用std::launch::async参数的方法创建异步任务运行子线程。而如果系统资源不够用的话则使用std::launch::deferred参数方法延迟调用该入口函数方法,并且不开子线程。也就是说带了这个参数,系统会自己决定该入口函数是异步运行还是同步运行。
2,经过1的介绍也就不难理解为什么我们的async函数模板不加参数时总是和std::launch::async参数行为一样了,因为我们在自己的电脑上试验的时候,系统资源一般都是够的。
2.3.1 async不确定性问题的解决(wait_for()方法)
不加额外参数的async调用时让系统自行决定,是否创建新线程。
std::future result = std::async(mythread);
问题焦点在于这个写法,任务到底有没有被推迟执行。
一,先介绍future对象的wait_for()方法,学了该方法就可以解决async不确定性的问题,future对象的wait_for()方法返回结果用future_status这个枚举类型去接。
std::future_status是枚举类型,表示异步任务的执行状态。类型的取值有
std::future_status::timeout
std::future_status::ready
std::future_status::deferred
#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()