C++ future async promise 用法详解 - packaged_task

packaged_task

背景

  • 启发于function pointer
  • 采用类似 promise 的设计
  • 方便的获取线程运行结果

原理

  • 生产者 - 消费者模型

基本函数

  • 生产函数,分两步

    • 设置value或者exception
    • 设置shared state
    // 设置value或者exception后,立即将shared state设置为ready
    void operator()(Args... args);
    // 设置value或者exception后,在当前线程退出后才把shared state设置为ready
    void make_ready_at_thread_exit (args... args);
    
  • 消费函数

    获取future,负责保存shared state和value/exception

    template <class T>
    future<T> get_future();
    
  • 其他函数

    // 构造函数,可采用any Callable target (function, lambda expression, bind expression, or another function object) 
    packaged_task() noexcept;
    template <class Fn>
    explicit packaged_task (Fn&& fn);
    packaged_task (packaged_task&) = delete;
    packaged_task (packaged_task&& x) noexcept;
    // 只可用移动赋值运算
    packaged_task& operator= (packaged_task&& rhs) noexcept;
    packaged_task& operator= (const packaged_task&) = delete;
    // swap 函数
    void swap (packaged_task& x) noexcept;
    template <class Ret, class... Args>
    void swap (packaged_task<Ret(Args...)>& x, packaged_task<Ret(args...)>& y) noexcept;
    // Reset 函数,效果相当于重新构造
    void reset();
    // 是否有 callable target
    bool valid() const noexcept;
    

基本用法

  • 生产者post task,自定义task执行,消费者pop 状态

  • 单生产,单消费不会有异常;多生产/多消费需要处理异常状态

  • 支持线程池的使用

    #include <iostream>
    #include <cmath>
    #include <thread>
    #include <future>
    #include <functional>
    
    int f(int x, int y) { return std::pow(x,y); }
     
    void task_lambda() {
        std::packaged_task<int(int,int)> task([](int a, int b) {
            return std::pow(a, b); 
        });
        std::cout << "task valid:\t" << task.valid() << '\n'; 
        std::future<int> result = task.get_future();
        task(2, 9);
        std::cout << "task_lambda:\t" << result.get() << '\n';
        task.reset();
        std::future<int> result2 = task.get_future();
        task(2, 10);
        std::cout << "task_lambda:\t" << result2.get() << '\n';
        task.reset();
        std::future<int> result3 = task.get_future();
        new std::thread([&](){
            task.make_ready_at_thread_exit(2, 11);
        });
        std::cout << "task_lambda:\t" << result3.get() << '\n';
    }
     
    void task_bind() {
        std::packaged_task<int()> task(std::bind(f, 2, 11));
        std::future<int> result = task.get_future();
        task();
        std::cout << "task_bind:\t" << result.get() << '\n';
    }
     
    void task_thread() {
        std::packaged_task<int(int,int)> task(f);
        std::future<int> result = task.get_future();
        std::thread task_td(std::move(task), 2, 10);    // thread 支持 packaged_task 构造
        task_td.join();
        std::cout << "task_thread:\t" << result.get() << '\n';
    }
     
    int main() {
        task_lambda();
        task_bind();
        task_thread();
    }
    

posted @ 2021-05-13 23:52  Jamgun  阅读(130)  评论(0编辑  收藏  举报