std::async的使用

1.std::async简介

C++11提供了thread线程库,可以通过std::thread启动线程,同时也提供了std::async来执行异步任务。std::async与std::thread对象等待的方式不同,std::async会返回一个std::future对象,这个对象持有最终计算出来的结果,当需要这个值的时候,只需要调用这个对象的get()成员函数,并且会阻塞线程直到期望值状态变为就绪。

2.std::async使用

async的使用方式跟std::thread一致。

2.1基本使用

int do_some_thing()
{
    int nRet = 100;
    std::this_thread::sleep_for(std::chrono::milliseconds(100));
    
    return nRet;
}

int main()
{
   
    std::future<int> data = std::async(do_some_thing);
    std::cout << "value:" << data.get() << std::endl;

    return 0;
}

这段程序输出的结果为100,即std::async执行的函数do_some_thing的返回值,保存在std::future<int>对象中。std::future是一个模板类,表示一个期望值, 当调用data.get()的时候,会阻塞线程,直到std::async执行完成。

2.2参数传递

std::async允许添加额外的参数,第一个参数是指向成员函数的指针,第二个参数提供有这个函数成员类的具体对象(也可以是引用等),剩余的参数可以作为成员函数的参数传入。

struct Foo
{
    int add(int a, int b)
    {
        return a + b;
    }

    void Test_Function()
    {
        std::cout << __FUNCTION__ << std::endl;
        std::this_thread::sleep_for(std::chrono::seconds(1));
    }
};

int main()
{
 
    Foo f;
    auto data1  = std::async(&Foo::add,&f,1,2);
    std::cout << "data1:" << data1.get() << std::endl;

    auto data2 = std::async(&Foo::Test_Function,&f);
    data2.wait();

    return 0;
}

3.std::async启动策略

std::async可以决定是否启动一个线程,可以给std::async传递一个参数,来决定是否需要启动一个线程来运行,这个参数是std::launch。如果是std::launch::async,表明函数必须在其独立的线程上运行。如果是std::launch::defered表面函数调用被延迟到get()或者wait()函数调用的时候才执行。std::launch::defered|std::launch::async表明实现可以选择这两种方式中的一种。

3.1std::launch::async

int do_some_thing()
{
    int nRet = 100;

    std::cout << "thread_id1:" << std::this_thread::get_id() << std::endl;
    std::this_thread::sleep_for(std::chrono::seconds(5));
    std::cout << "thread_id2:" << std::this_thread::get_id() << std::endl;
    return nRet;
}


int main()
{
    std::cout << "main_id1:" << std::this_thread::get_id() << std::endl;
    auto data = std::async(std::launch::async,do_some_thing);
    std::this_thread::sleep_for(std::chrono::seconds(1));
    //当调用get的时候,会阻塞线程,当do_some_thing执行完成后,才会输出main_id2
    //如果不调用get,会先输出main_id2,主线程继续往下走执行任务,互不干扰
    data.get();
    std::cout << "main_id2:" << std::this_thread::get_id() << std::endl;

    return 0;
}

这段代码输出的main_id和thread_id是不一样的,表明do_some_thing是那另一个线程中去执行的。

3.2std::launch::deferred

int do_some_thing()
{
    int nRet = 100;
    std::cout << "thread_id:" << std::this_thread::get_id() << std::endl;
    std::this_thread::sleep_for(std::chrono::milliseconds(100));
    
    return nRet;
}

int main()
{
   
    std::cout << "main_id:" << std::this_thread::get_id() << std::endl;
    std::future<int> data = std::async(std::launch::deferred,do_some_thing);
    //阻塞线程,直到任务执行完成,如果未调用wait函数,贼不会执行该任务
    //函数被延迟到当std::future对象调用wait或者get的时候才会执行
    data.wait();
   
    return 0;
}

这段代码输出的mian_id和thread_id是一致的,同时如果将data.wait()函数屏蔽后,只会输出main_id,而不会输出thread_id,因为只有调用data.wait()或者data.get()的时候,对应的函数do_some_thing才会去执行。

3.3std::launch::deferred|std::launch::async

int do_some_thing()
{
    int nRet = 100;
    std::cout << "thread_id:" << std::this_thread::get_id() << std::endl;
    std::this_thread::sleep_for(std::chrono::milliseconds(100));
    
    return nRet;
}

int main()
{
   
    std::cout << "main_id:" << std::this_thread::get_id() << std::endl;
                 
     std::future<int> data =  std::async(std::launch::deferred|std::launch::async,do_some_thing);

   
    return 0;
}

这段代码的输出跟std::launch::async一样(Ps:有人说选择哪种策略是根据编译器或者标准库来选择的,不同的编译器或标准库可能会选择不同的策略,这个我也不太清楚,有没有大佬指点一二)

4.std::async和std::thread对比

std::thread和std::async之间存在一定的差别

1.std::async返回一个期望值,通过期望值(std::future)可以得到执行任务的结果

2.std::async可以指定相关策略,可以启动一个线程来执行异步任务,也可以不启动一个新的线程,std::thread必定会创建一个新线程

3.std::async未提供join()或者detach()函数,std::thread等待子线程完成任务可以调用join()函数,要想等待异步任务完成可以调用get()或者wait()函数。另外std::thread可以调用detach将子线程分离,当主线程退出后,子线程仍然可以完成对应的任务,如果调用std::async,主线程退出后,异步任务还没有执行完,情况就要复杂的多。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值