天天看点

【C++11多线程】线程结果future1 std::async2 std::packaged_task3 std::promise4 std::shared_future参考

索引

  • 1 std::async
  • 2 std::packaged_task
  • 3 std::promise
  • 4 std::shared_future
  • 参考

1 std::async

先用std::async启动一个异步任务,它返回一个持有计算结果的std::future,通过std::future::get即可阻塞线程,直到期值的状态为ready并返回该结果

int f()
{
    return 1;
}

int main()
{
    std::future<int> ft = std::async(f);
    std::cout << ft.get(); // 1
}
           
int f();
// 函数必须异步执行,即运行在不同的线程上
auto ft1 = std::async(std::launch::async, f);
// 函数只在返回的期值调用get或wait时运行
auto ft2 = std::async(std::launch::deferred, f);
// 不指定时的默认启动策略是对两者进行或运算的结果
// auto ft3 = std::async(f)等价于
auto ft3 = std::async(std::launch::async | std::launch::deferred, f);
           

2 std::packaged_task

packaged_task类模板也是定义于future头文件中,它包装任何可调用 (Callable) 目标,包括函数、 lambda 表达式、 bind 表达式或其他函数对象,使得能异步调用它,其返回值或所抛异常被存储于能通过 std::future 对象访问的共享状态中。简言之,将一个普通的可调用函数对象转换为异步执行的任务。通过packaged_task包装后,可以通过thread启动或者仿函数形式启动,其执行结果返回值或所抛异常被存储于能通过 std::future 对象访问的共享状态中。

#include <iostream>           // std::cout
#include <thread>             // std::thread
#include <chrono>
#include <future>

using namespace std;
//普通函数
int Add(int x, int y)
{
    return x + y;
}


void task_lambda()
{
    //包装可调用目标时lambda
    packaged_task<int(int,int)> task([](int a, int b){ return a + b;});
    
    //仿函数形式,启动任务
    task(2, 10);
    
    //获取共享状态中的值,直到ready才能返回结果或者异常
    future<int> result = task.get_future();
    cout << "task_lambda :" << result.get() << "\n";
}

void task_thread()
{
    //包装普通函数
    std::packaged_task<int (int,int)> task(Add);
    future<int> result = task.get_future();
    //启动任务,非异步
    task(4,8);
    cout << "task_thread :" << result.get() << "\n";
        
    //重置共享状态
    task.reset();
    result = task.get_future();

    //通过线程启动任务,异步启动
    thread td(move(task), 2, 10);
    td.join();
    //获取执行结果
    cout << "task_thread :" << result.get() << "\n";
}

int main(int argc, char *argv[])
{
    task_lambda();
    task_thread();

    return 0;
}

           

3 std::promise

一个std::promise只能关联一个std::future,关联多次时将抛出std::future_error异常

std::promise<int> ps;
std::future<int> ft = ps.get_future();
ps.set_value(42); // set_value还会将状态设置为就绪
std::cout << ft.get(); // 42
           
void f(std::promise<void> ps)
{
    std::this_thread::sleep_for(std::chrono::seconds(1));
    ps.set_value();
}

int main()
{
    std::promise<void> ps;
    std::future<void> ft = ps.get_future();
    std::thread t(f, std::move(ps));
    ft.wait(); // 阻塞直到set_value,相当于没有返回值的get
    t.join();
}
           

4 std::shared_future

std::future调用get后就无法再次get,也就是说只能获取一次数据,此外还会导致所在线程与其他线程数据不同步。std::shared_future就可以解决此问题

//第一种
std::promise<int> ps;
std::future<int> ft(ps.get_future());
std::shared_future<int> sf(std::move(ft));

//第二种
// std::future隐式转换为std::shared_future
std::promise<int> ps;
std::shared_future<int> sf(ps.get_future());

//第三种
std::promise<int> ps;
auto sf = ps.get_future().share();
           

参考

1.https://downdemo.gitbook.io/cpp-concurrency-in-action-2ed

2.https://blog.csdn.net/c_base_jin/article/details/79541301