一、std::async深入谈
1.1 std::async参数详述
async用来创建一个异步任务
#include <thread>
#include <future>
int mythread()
{
cout << "mythread() start threadid = " << std::this_thread::get_id() << endl;
return 1;
}
int main()
{
cout << "main start threadid = " << std::this_thread::get_id() << endl;
std::future<int> result = std::async(mythread);
cout << result.get() << endl;
}
现象:
main start threadid = 140446991939392
mythread() start threadid = 140446973945600
1
std::async的第一个参数
前面介绍过参数 std::launch::deferred
【延迟调用】和std::launch::async
【强制创建一个线程】
1.std::launch::deferred
:
表示线程入口函数调用被延迟到std::future
对象调用wait()
或者get()
函数调用才执行。如果wait()
和get()
没有调用,则不会创建线程并执行线程入口函数;如果主线程中调用wait()
和get()
,实际上也不会创建新线程,而是在主线程中执行入口函数
2.std::launch::async
:
表示强制这个异步任务在 新线程上执行,在调用std::async()
函数的时候就开始创建线程,std::async
默认的就是这个标记
3.std::launch::deferred|std::launch::async
:
这里的“|”意味着调用async
的行为可能是“创建新的线程并立即执行”或者“没有创建线程并且延迟到调用result.get()才开始执行任务入口函数”。系统会自行评估进行选择。
4.std::async
不带这个标记时(std::async不给额外参数,只给一个线程入口函数名字),默认是第三种情况,系统自行决定是异步(创建新线程)还是同步(不创建新线程)方式运行
第九节说“按std::launch::async
执行”是不对的
1.2 std::async和std::thread区别
最明显的不同就是async
有时候并不创建线程
std::thread
创建线程,如果系统资源紧张,创建线程失败,那么程序就会报异常崩溃(有脾气)
int mythread()
{
return 1;
}
int main()
{
std::thread myobj(mythread);
myobj.join();
}
std::async
创建异步任务,可能创建也可能不创建任务。并且async
调用方法很容易拿到线程(入口函数)的返回值;
由于系统资源限制:
(1)如果调用std::thread
创建的线程太多,则可能创建失败,系统报告异常,不会崩溃。
(2)如果调用std::async
,一般不会报异常、不会崩溃,因为如果系统资源紧张导致无法创建新线程的时候,那么这个异步任务就运行在执行这条get()
语句所在的线程上。
如果强制std::async一定要创建新线程,那么就必须使用std::launch::async。承受的代价就是系统资源紧张时,程序崩溃。
(3)经验:一个程序里,线程数量不宜超过100-200。
1.3 std::async不确定性问题的解决
不加额外参数的std::async调用,让系统自行决定是否创建新线程。
问题焦点在于std::future<int> result = std::async(mythread);
写法,这个异步任务到底有没有被推迟执行,可以通过result.wait_for()函数来判断:
std::future<int> result = std::async(mythread);
std::future_status status = result.wait_for(std::chrono::seconds(0s)); //0s的语法没问题,operator ""s
if (status == std::future_status::deferred)
{
// 如果async的第一个参数被设置为std::launch::deferred,则本条成立
cout << "线程被延迟执行" << endl;
cout << result.get() << endl; // 这时候线程入口函数才会执行
}
else
{
cout<<"任务没有被推迟"<<endl;
if (status == std::future_status::ready)
{
cout << "线程成功执行完毕并返回!" << endl;
cout << result.get() << endl;
}
else if (status == std::future_status::timeout)
{
cout << "超时线程没执行完!" << endl;
cout << result.get() << endl;
}
}
}