c++11多线程中的std::async异步函数

https://blog.csdn.net/li1615882553/article/details/86252813

 

目录

写在前面

解析

future类成员函数

wait_for以及wait_until返回值类型

get函数

valid函数

wait_for函数

std::launch类型

参考博客

写在前面
如果有一个需要长时间运算的线程,需要计算出最终的有效值,但是现在不迫切需要这个数值,如果我们使用std::thread的话,着一定是不可行的,因为std::thread不可以接收返回值,这里需要使用std:async函数模板

我们可以使用std::async创建一个异步任务,返回std:future对象,这个std:future对象持有线程返回的数据

解析
std::saync是一个类模板,他的构造函数包含两种形式:

template <class Fn, class... Args>
  future<typename result_of<Fn(Args...)>::type>
    async (Fn&& fn, Args&&... args);
template <class Fn, class... Args>
  future<typename result_of<Fn(Args...)>::type>
    async (launch policy, Fn&& fn, Args&&... args);
可以知道,std::async的使用方法和std::thread类似,但是在第二个构造函数中,存在一个std::launch类型的参数,后面详细说明此参数,并且std::async都会返回一个std::future对象,用来存放返回的数据。

#include <iostream>
#include <future>
#include <string>
#include <vector>
 
int mythread()
{
    std::cout << "mythread() start thread id =" << std::this_thread::get_id() << std::endl;
    std::this_thread::sleep_for(std::chrono::seconds(5));
    std::cout << "mythread() start thread id =" << std::this_thread::get_id() << std::endl;
    return 5;
}
int main()
{
    std::cout << "main function id:" << std::this_thread::get_id() << std::endl;
    std::future<int> result = std::async(mythread);
    //或者使用auto自动判断返回值类型:auto result = std::async(mythread);
 
    std::cout << "continue......!" << std::endl;
    std::cout << result.get() << std::endl;
    
    std::cout << "main function finish!" << std::endl;
    return 0;
}
可以看到future变量可以接受线程返回的数值,并且使用get()函数得到返回的数值。

future对象可以有被以下三种方式创建

async

promise::get_future
packaged_task::get_future
future类成员函数
share    返回一个std::shared_future对象,调用函数后future对象不和任何共享状态关联,此时future状态不再是valid(有效的)
get    当与该 std::future 对象相关联的共享状态标志变为 ready 后,调用该函数将返回保存在共享状态中的值,如果共享状态的标志不为 ready,则调用该函数会阻塞当前的调用者,而此后一旦共享状态的标志变为 ready,get 返回 Provider 所设置的共享状态的值或者异常(如果抛出了异常)。
valid    检查当前future对象是否有效,通过上述三种方式创建的对象是vaild,还可以使用move将其变为valid
wait    
等待与当前std::future 对象相关联的共享状态的标志变为 ready.

如果共享状态的标志不是 ready,调用该函数会被阻塞当前线程,直到共享状态的标志变为 ready

一旦共享状态的标志变为 ready,wait() 函数返回,当前线程被解除阻塞

wait_for    和wait函数类似,需要设置一个时间段rel_time,如果共享状态的标志在时间段结束之前没有被Provider设置为valid,则调用wait_for的线程被堵塞,在等待了rel_time时间后,wait_for函数返回
wait_until    和wait函数类似,需要设置一个系统绝对时间点abs_time,如果共享状态的标志在该时间点到来之前没有被 Provider 设置为 ready,则调用 wait_until 的线程被阻塞,在 abs_time 这一时刻到来之后 wait_until() 返回
wait_for以及wait_until返回值类型
返回类型为future_status,表示导致函数返回的原因:

future_status::ready    共享状态的标志已经变为 ready,即 Provider 在共享状态上设置了值或者异常
future_status::timemout    超时,即在规定的时间内共享状态的标志没有变为 ready。
future_status::deferred    共享状态包含一个 deferred 函数。如在saync中第一个参数指定为std::launch::deferred
get函数
get函数的源码为:

void get()
        {    // block until ready then return or
            // throw the stored exception
        future _Local{_STD move(*this)};
        _Local._Get_value();
        }
可以看到在get函数中新建了一个_Local的新对象,使用移动语义(一般变量或者函数前面以'_'开头,表示为内部使用的对象或者函数),然后得到_Local的value,这样的话,future对象就会变为无效的,即调用vaild函数会返回false ,因为这里使用移动语义,新对象_Local对象在get函数中被销毁,也就是说future对象只可以调用一次get函数,如果要调用多次get函数,可以使用shared_future对象(使用复制语义)

valid函数
#include <iostream>
#include <future>
#include <string>
#include <vector>
 
int get_value()
{
    return 10;
}
int main()
{
    std::future<int> foo, bar;
    foo = std::async(get_value);
    bar = std::move(foo);        //使用移动构造函数,foo变为无效,bar变为有效
 
    if (foo.valid())
        std::cout << "foo's value:" << foo.get() << std::endl;
    else
        std::cout << "foo is not valid\n";
 
    if (bar.valid())
        std::cout << "bar's value:" << bar.get() << std::endl;
    else
        std::cout << "bar is not valid\n";
    return 0;
}
//栗子来源:http://www.cplusplus.com/reference/future/future/valid/
wait_for函数
#include <iostream>
#include <future>
#include <string>
#include <vector>
bool is_prime(int x) {
    for (int i = 2; i<x; ++i) if (x%i == 0) return false;
    return true;
}
 
int main()
{
    // call function asynchronously:
    std::future<bool> fut = std::async(is_prime, 700020007);
 
    // do something while waiting for function to set future:
    std::cout << "checking, please wait";
    std::chrono::milliseconds span(100);
    while (fut.wait_for(span) == std::future_status::timeout)
        std::cout << '.';
 
    bool x = fut.get();
 
    std::cout << "\n700020007 " << (x ? "is" : "is not") << " prime.\n";
 
    return 0;
}
//栗子来源:http://www.cplusplus.com/reference/future/future/wait_for/
std::launch类型
std::launch类型在async的第二种构造函数中看到,一种枚举类型,原型为:

        // ENUM launch
enum class launch {    // names for launch options passed to async
    async = 0x1,
    deferred = 0x2
    };
类型    作用
std::launch::async     
 异步任务会在另外一个线程中调用,并通过共享状态返回异步任务的结果(一般是调用 std::future::get() 获取异步任务的结果),简单说为:

在调用async函数的时候就开始创建线程,并在新线程运行

std::launch::deferred     
异步任务将会在共享状态被访问时调用,相当与按需调用(即延迟(deferred)调用),简单说为:

线程入口函数调用被延迟到std::future的wait或者get函数调用时才执行,如果后面不调用wait或者get函数,就不会执行saync中的函数

std::launch::deferred  |  std::launch::async     默认情况下使用此种参数,表示编译器会根据计算机现在的情况自行选择对应的执行方式
#include <iostream>
#include <future>
#include <string>
#include <vector>
 
int mythread()
{
    std::cout << "mythread() start thread id =" << std::this_thread::get_id() << std::endl;
    std::this_thread::sleep_for(std::chrono::seconds(5));
    std::cout << "mythread() start thread id =" << std::this_thread::get_id() << std::endl;
    return 5;
}
int main()
{
    std::cout << "main function id:" << std::this_thread::get_id() << std::endl;
    std::future<int> result = std::async(std::launch::deferred,mythread);
    //std::future<int> result = std::async(std::launch::async, mythread);
 
    std::cout << "continue......!" << std::endl;
    std::cout << "main function finish!" << std::endl;
    std::cout << result.get() << std::endl;
    
    return 0;
}
std::launch::deferred 情况下可以发现,并没有创建新线程,而是调用get函数的时候,在主线程中执行对应的函数

std::launch:: async :及正常调用情况,创建新线程执行

 

#include <iostream>
#include <future>
#include <string>
#include <functional>
#include <algorithm>
#include <vector>
 
int mythread()
{
    std::cout << "mythread() start thread id =" << std::this_thread::get_id() << std::endl;
    std::this_thread::sleep_for(std::chrono::seconds(5));
    std::cout << "mythread() start thread id =" << std::this_thread::get_id() << std::endl;
    return 5;
}
 
int main()
{
    std::future<int> f = std::async(std::launch::deferred, mythread);
    std::future_status a1 = f.wait_for(std::chrono::seconds(0));
    if (a1 == std::future_status::deferred)
    {
        std::cout << "线程正延迟执行,等待get或者wait函数调用\n";
        f.get();
    }
    else
    {
        if (a1 == std::future_status::ready)
        {
            std::cout << "线程执行完毕\n";
            f.get();
        }
        else
        {
            std::cout << "线程未执行完毕\n";
            f.get();
        }
    }
    return 0;
}
 

参考博客
C++11 并发指南四(<future> 详解三 std::future & std::shared_future) 

http://www.cplusplus.com/reference/future/future/

《C++11并发与多线程视频课程》 视频地址:http://edu.51cto.com/course/15287.html
————————————————
版权声明:本文为CSDN博主「阿_波_」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/li1615882553/article/details/86252813

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值