1 详解std::async

1.1 std::async

作用

std::async可以异步在一个独立线程中运行线程函数F,并且返回一个存储线程函数F运行结果的std::future,简而言之就是C++提供的高级异步接口。

函数原型

template< class Function, class... Args >
std::future<typename std::result_of<typename std::decay<Function>::type(
        typename std::decay<Args>::type...)>::type>
    async( Function&& f, Args&&... args );

template< class Function, class... Args >
std::future<std::invoke_result_t<std::decay_t<Function>,
                                 std::decay_t<Args>...>>
    async( Function&& f, Args&&... args );

template< class Function, class... Args >
[[nodiscard]] std::future<std::invoke_result_t<std::decay_t<Function>,
                                               std::decay_t<Args>...>>
    async( Function&& f, Args&&... args );

template< class Function, class... Args >
std::future<typename std::result_of<typename std::decay<Function>::type(
        typename std::decay<Args>::type...)>::type>
    async( std::launch policy, Function&& f, Args&&... args );

template< class Function, class... Args >
std::future<std::invoke_result_t<std::decay_t<Function>,
                                 std::decay_t<Args>...>>
    async( std::launch policy, Function&& f, Args&&... args );

template< class Function, class... Args >
[[nodiscard]] std::future<std::invoke_result_t<std::decay_t<Function>,
                                               std::decay_t<Args>...>>
    async( std::launch policy, Function&& f, Args&&... args );

函数参数

std::async主要的参数如下

  • f:线程函数,可接受function, lambda expression, bind expression, or another function object

  • args...:线程函数参数

  • policy:可选std::launch::asyncstd::launch::deferred,默认为std::launch::async | std::launch::deferred两种策略的合集。

线程创建策略的具体含义:

  • std::launch::async调度策略意味着函数必须异步执行,即在另一线程执行
  • std::launch::deferred调度策略意味着函数可能只会在std::async返回的future对象调用get或wait时执行。那就是,执行会推迟到其中一个调用发生。当调用get或wait时,函数会同步执行,即调用者会阻塞直到函数运行结束。如果get或wait没有被调用,函数就绝对不会执行
  • 如果没有显示指定创建策略,则默认策略为std::launch::async | std::launch::deferred,那么默认情况下这种行为是未定义的,有可能是std::launch::async,也有可能是std::launch::deferred,到底是异步执行还是惰性等待执行取决于具体的代码实现,所以如果需要异步执行的函数一定要显式指定std::launch::async

函数返回值

返回存储线程函数执行结果的std::future

std::future提供了一种访问异步操作结果的机制,它提供了在主线程中在未来的某个时间以同步的方式获取异步函数执行的结果。

std::future有三种状态:

  • deferred:异步操作未开始
  • ready:异步操作已经完成
  • timeout:异步操作超时

std::future获取结果的方式有三种:

  • get:等待异步操作结束并返回结果
  • wait:等待异步操作结束,但没有返回值
  • wait_for:超时等待返回结果

1.2 std::async的使用

(1) 普通函数做线程函数

#include <iostream>
#include <future>

int sum(int start, int end)
{
    int sum = 0;
    for (int i = start; i < end; ++i)
    {
        sum += i;
    }
    return sum;
}

int main()
{
    std::future<int> res1 = std::async(&sum, 1, 1000); // 默认线程创建策略
    std::future<int> res2 = std::async(std::launch::async, &sum, 1, 1001); // async创建策略
    std::future<int> res3 = std::async(std::launch::deferred, &sum, 1, 1002); // deferred创建策略

    std::cout << "result1 = "<< res1.get() << std::endl;
    std::cout << "result2 = " << res2.get() << std::endl;
    std::cout << "result3 = " << res3.get() << std::endl;

    return 0;
}

(2) lambda做线程函数

#include <iostream>
#include <future>

int main()
{
    int start = 0;
    int end = 1000;
    std::future<int> res1 = std::async(std::launch::async,[start,end]() {
        int sum = 0;
        for (int i = start; i < end; ++i)
        {
            sum += i;
        }
        return sum;
    });

    std::cout << "result1 = " << res1.get() << std::endl;

    return 0;
}

(3) std::function做线程函数

#include <iostream>
#include <future>
#include <functional>

int sum(int start, int end)
{
    int sum = 0;
    for (int i = start; i < end; ++i)
    {
        sum += i;
    }
    return sum;
}

int main()
{
    int start = 0;
    int end = 1000;

    std::function<int(int, int)> f = std::bind(&sum,std::placeholders::_1, std::placeholders::_2);

    std::future<int> res1 = std::async(f,start,end);


    std::cout << "result1 = " << res1.get() << std::endl;

    return 0;
}

参考