Solid foundation (4): std::async function

In a multi-threaded programming environment, std::threadclasses are generally used to create sub-threads, but sometimes system resources are tight, or sub-threads may be required to return some results. In this case, it can be used std::async(), the function can determine whether to create a new thread (that is, start an asynchronous task) according to the specific situation; the return value can be saved in std::futurean object of type (a class template).

#include<iostream>
#include<future>
int tmain(){
    std::cout<<"tmain, thread id = "<<std::this_thread::get_id()<<std::endl;
    return 5;
}

int main(){
    std::cout<<"main, thread id = "<<std::this_thread::get_id()<<std::endl;
    std::future<int>res = std::async(tmain);
    cout<<res.get()<<endl;//阻塞,等待返回值
    std::cout<<"main end"<<std::endl;
    return 0;
}
复制代码

std::async()The function may create a new thread to execute the entry function tmain()and then return the result to a variable res. The function can have additional parameters: std::launch::deferredand std::launch::async, the former means that the execution of the thread entry function is delayed until the get()method is called, but if the get()method is not called, it means that there is no such statement, and it can be found that no new thread is created at this time; the latter is A new thread will be created. The situation without parameters is equivalent to std::launch::deferred|std::launch::asyncthat, at this time, the system decides whether to create a new thread according to the specific situation.

//main()
#include<iostream>
#include<future>
int tmain1(int val){
    std::cout<<"tmain1, thread id = "<<std::this_thread::get_id()<<std::endl;
    std::chrono::milliseconds dura(5000);
    std::this_thread::sleep_for(dura);
    std::cout <<"tmain1: "<< getTime() << std::endl;
    return val;
}
int main(){
    std::cout<<"main, thread id = "<<std::this_thread::get_id()<<endl;
    std::future<int>res1 = std::async(std::launch::deferred,tmain1,6);
    std::future<int>res2 = std::async(std::launch::async,tmain1,8);
    std::cout<<res2.get()<<std::endl;
    std::cout<<res1.get()<<std::endl;
    std::cout<<"main end"<<std::endl;
    return 0;
}
复制代码

In the above code, res1the line where the variable is located does not create a new thread, but res2the line where the variable is located creates a new thread, as shown in the following figure. At the same time, res2the get()method is blocked first, so 8 is output first , then res1the get()method is blocked, and then 6 is output.
image.png

std::futureIt is also possible to further determine whether the thread has been executed or whether it has been delayed:

...
int main(){
    std::cout<<"main, thread id = "<<std::this_thread::get_id()<<endl;
    std::future<int>res = std::async(tmain1,6);
    std::future_status status = res.wait_for(std::chrono::seconds(1));//程序在此处等待1秒
    if(status == std::future_status::timeout){//创建新线程
        std::cout<<"线程执行超时"<<std::endl;
        std::cout<<res.get()<<std::endl;
    }
    else if(status == std::future_status::timeout){//创建新线程
        std::cout<<"线程执行完成"<<std::endl;
        std::cout<<res.get()<<std::endl;
    }
    else//if(status == std::future_status::deferred)//不创建新线程
    {
        std::cout<<"线程延迟执行"<<std::endl;
        std::cout<<res.get()<<std::endl;//入口函数在此处执行并返回结果
    }
    std::cout<<"main end"<<std::endl;
}
复制代码

上述代码中,wait_for()函数的等待时间可以理解成分配给线程的执行时间(如果创建了新线程),由于线程入口函数中沉睡了5s,大于等待时长,所以上述代码执行第一个if语句,否则,执行第二个if语句。但即使线程没有执行完,也会阻塞在get()方法处等待结果返回。如果async()函数使用了std::launch::deferred参数,则wait_for()无效,会执行第三个if语句。上述代码事实上可以确定async()函数不带参数或者带两个参数时带来的不确定性问题,即异步任务是否被延迟执行。
wait_for()函数原型如下:

#define std::future_status std::_Future_status
template<class _Rep, class _Per>
_Future_status wait_for(const chrono::duration<_Rep,_Per>&_Rel_time)const{
    if(!valid())
        _Throw_future_error(make_error_code(future_errc::no_state));
    return (_Assoc_state->_Wait_for(_Rel_time));
}
_Future_status _Wait_for(const chrono::duration<_Rep,_Per>&_Rel_time){
    unique_lock<mutex>_Lock(_Mtx);
    if(_Has_deferred_function())
        return _Future_status::deferred;
    if(_Cond.wait_for(_Lock,_Rel_time,_Test_ready(this)))
        return _Future_status::ready;
    return _Future_status::timeout;
}
_Future
复制代码

从上上面代码中第二个函数可以很容易看出来,如果检测到std::launch::deferred参数,则直接返回deferred状态;否则,等待_Rel_time并使用_Test_ready检测是否有超时信号,如果没有,在返回ready状态,否则,返回timeout状态。

Guess you like

Origin juejin.im/post/7059604972198952973