Base sólida (4): función std::async

En un entorno de programación de subprocesos múltiples, las std::threadclases generalmente se usan para crear subprocesos, pero a veces los recursos del sistema son escasos o se pueden requerir subprocesos para devolver algunos resultados. En este caso, se puede usar std::async(), la función puede determinar si crear un nuevo hilo (es decir, iniciar una tarea asíncrona) de acuerdo con la situación específica; el valor devuelto se puede guardar en std::futureun objeto de tipo (una plantilla de clase) .

#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()La función puede crear un nuevo hilo para ejecutar la función de entrada tmain()y luego devolver el resultado a una variable res. La función puede tener parámetros adicionales: std::launch::deferredy std::launch::async, lo primero significa que la ejecución de la función de entrada de subprocesos se retrasa hasta get()que se llama al método, pero si get()no se llama al método, significa que no existe tal declaración y se puede encontrar que no se crea ningún nuevo hilo; este último es Se creará un nuevo hilo. La situación sin parámetros equivale a std::launch::deferred|std::launch::asyncque, en este momento, el sistema decide si crea un nuevo hilo de acuerdo a la situación específica.

//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;
}
复制代码

En el código anterior, res1la línea donde se encuentra la variable no crea un nuevo hilo, pero res2la línea donde se encuentra la variable crea un nuevo hilo, como se muestra en la siguiente figura. Al mismo tiempo, res2el get()método se bloquea primero, por lo que primero se emite 8 , luego se bloquea res1el get()método y luego se emite 6.
image.png

std::futureTambién es posible determinar aún más si el subproceso se ha ejecutado o si se ha retrasado:

...
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状态。

Supongo que te gusta

Origin juejin.im/post/7059604972198952973
Recomendado
Clasificación