c++ packaged task 使用详解

c++ packaged task 使用详解

std::packaged_task

  • 头文件 #include

  • 类模板,模板参数为函数签名,定义如下:

    template<class R, class ...Args>
    class packaged_task<R(Args...)>;
    
  • 作用:

    • 将 future 对象与任何可调用目标(函数、 lambda 表达式、 bind 表达式或其他函数对象)封装为一个异步任务,当执行该任务时(一般为异步执行),会调用内部关联的可调用目标,并将返回值或者调用过程中抛出的异常保存于 future 中,并令 future 准备就绪;
    • 一般用于将函数封装成异步任务,而不是直接创建线程。它常常与 std::thread、std::async 等结合使用,以支持更灵活的异步编程模型;
  • 使用方法:

    • 创建一个 std::packaged_task 对象;
    • 调用 packaged_task 对象的 get_future() 方法,获取与任务关联的 std::future 对象,用于获取任务的结果或异常;
    • 将 packaged_task 对象作为参数传递给一个线程、线程池或其他异步执行方式,以便在后台执行任务;
    • 在需要的时候,通过 std::future 对象的 get() 方法获取异步任务的结果,或者通过其他方法获取任务的状态和控制任务的行为;

std::packaged_task 成员函数

  • get_future:返回与调用目标相关联的 future 对象,对于每一个 packaged_task,只能调用一次。
  • make_ready_at_thread_exit:相当于直接调用内部的可调用对象,只有在调用该方法的线程结束并且所有线程局部对象被销毁后,与之关联的 future 才会准备就绪。
  • reset:重置状态,抛弃先前执行的结果。

std::packaged_task 使用例子

#include 
#include 
#include 
#include 
#include 

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::future<int> result = task.get_future();

    task(2, 9);
    printf("task lambda, result is %d\n", result.get());
}

void task_bind()
{
    std::packaged_task<int()> task(std::bind(f, 2, 11));
    std::future<int> result = task.get_future();

    task();
    printf("task bind, result is %d\n", result.get());
}

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);
    task_td.join();
    printf("task thread, result is %d\n", result.get());
}

int main()
{
    task_lambda();
    task_bind();
    task_thread();
}

make_ready_at_thread_exit 使用例子

#include 
#include 
#include 
#include 
#include 
#include 
#include 

void worker(std::future<void>& output)
{
    std::packaged_task<void(bool&)> my_task{ [](bool& done) { done = true; } };
    auto result = my_task.get_future();

    bool done = false;
    // 立即执行任务
    my_task.make_ready_at_thread_exit(done);
    // 函数已执行完成,done 已为 true
    printf("worker, done is %d\n", done);

    // 线程并未结束,局部对象仍未销毁,future 仍处于未就绪状态
    auto status = result.wait_for(std::chrono::seconds(0));
    if (status == std::future_status::timeout) {
        printf("worker, result is not ready\n");
    }

    output = std::move(result);
}

int main()
{
    std::future<void> result;
    // 开启线程,执行任务
    std::thread{worker, std::ref(result)}.join();

    // 线程结束,future 转为就绪状态
    auto status = result.wait_for(std::chrono::seconds(0));
    if (status == std::future_status::ready) {
        printf("main, result is ready\n");
    }
    return 0;
}

reset 使用例子

#include 
#include 
#include 

int main()
{
    std::packaged_task<int(int,int)> task([](int a, int b) {return std::pow(a, b);});
    std::future<int> result = task.get_future();
    task(2, 9);
    printf("2^9 = %d\n", result.get());

    task.reset();
    result = task.get_future();
    task(2, 10);
    printf("2^10 = %d\n", result.get());
}

你可能感兴趣的:(C++,并发编程,c++,开发语言)