std::packaged_task<返回类型(参数类型)>

std::packaged_task 概述

std::packaged_task 是 C++11 引入的标准库模板类,用于包装一个可调用对象(如函数、lambda 表达式、函数对象等),使其能够与 std::future 协同工作

简单来说,它将一个任务(可调用对象)包装起来,并允许你获取该任务的执行结果,这样你可以在一个线程中执行任务,并在另一个线程中获取其结果。

std::packaged_taskstd::futurestd::promise 一起,提供了异步任务执行和结果传递的功能。

基本功能

  • 包装可调用对象:通过 std::packaged_task 包装一个函数或可调用对象,类似于把任务“打包”起来。
  • 异步执行任务:将 packaged_task 对象交由线程执行,异步地处理任务。
  • 获取任务结果:通过关联的 std::future 对象,获取异步任务的结果。

用法和示例

1. 基本用法

下面是一个使用 std::packaged_task 包装函数并在不同线程中执行任务的简单示例:

#include <iostream>
#include <future>
#include <thread>
#include <chrono>

// 一个简单的函数,用于计算整数平方
int square(int x) {
    std::this_thread::sleep_for(std::chrono::seconds(2)); // 模拟耗时操作
    return x * x;
}

int main() {
    // 创建一个 std::packaged_task,包装 square 函数
    std::packaged_task<int(int)> task(square);

    // 获取关联的 std::future 对象,用于获取任务结果
    std::future<int> result = task.get_future();

    // 将任务交给一个线程异步执行
    std::thread t(std::move(task), 5); // 传递参数5给square函数
    t.detach(); // 分离线程

    // 在主线程中继续做其他事情
    std::cout << "Doing some work in the main thread..." << std::endl;

    // 获取任务的返回值,等待任务执行完成
    std::cout << "The result of square(5) is: " << result.get() << std::endl;

    return 0;
}

2. 逐步解析:

  1. 创建 packaged_task

    • std::packaged_task<int(int)> task(square); 创建一个 packaged_task,该任务包装了 square 函数,函数的返回值类型为 int,接受一个 int 参数。
  2. 获取 future 对象

    • std::future<int> result = task.get_future(); 获取与 packaged_task 关联的 std::future 对象,未来可以通过该 future 来获取任务的结果。
  3. 异步执行任务

    • std::thread t(std::move(task), 5); 创建一个线程并异步执行任务,传递参数 5square 函数。
  4. 等待结果

    • result.get() 用于获取任务的结果。这会阻塞主线程,直到任务完成并返回值。
  5. 分离线程

    • t.detach(); 分离线程,让任务在后台运行,主线程继续执行。

3. 使用 Lambda 表达式与 std::packaged_task

你可以使用 Lambda 表达式来包装任务:

#include <iostream>
#include <future>
#include <thread>

int main() {
    // 使用 lambda 表达式创建 packaged_task
    std::packaged_task<int(int, int)> task([](int a, int b) {
        return a + b;
    });

    // 获取 future 对象
    std::future<int> result = task.get_future();

    // 在新线程中异步执行
    std::thread t(std::move(task), 10, 20);
    t.detach();

    // 等待结果
    std::cout << "The result is: " << result.get() << std::endl;

    return 0;
}

在这个例子中,Lambda 表达式 [ ](int a, int b) { return a + b; } 被传递给 packaged_task,并在新线程中执行,主线程通过 result.get() 获取任务的返回值。

std::packaged_task 的常用成员函数

  • get_future()
    获取与 packaged_task 关联的 std::future 对象,用于获取异步任务的结果。

  • operator()
    调用 packaged_task,执行其中的任务。可以通过在新的线程中调用 std::move(task) 来异步执行。

  • 构造函数
    包装一个可调用对象,允许异步调用并获取返回结果。

std::asyncstd::thread 的区别

  • std::packaged_taskstd::future
    std::packaged_taskstd::future 联合使用时,更加灵活,能够包装任意可调用对象并传递给线程或异步任务,用户可以显式控制任务的启动时间。

  • std::async
    std::async 自动将任务放在后台线程中执行,返回 std::future,适合快速执行简单的异步任务,但不如 packaged_task 灵活。

  • std::thread
    std::thread 只是单纯的启动一个线程,无法直接获取线程执行的返回结果。而 std::packaged_task 能与 std::future 结合,使得结果可以通过 future 在主线程中获取。

总结

  • std::packaged_task 用于包装一个可调用对象,使其可以异步执行,并通过 std::future 获取其返回值。
  • std::packaged_task 适合在异步任务管理中灵活控制任务的执行,与 std::futurestd::threadstd::async 配合使用时能够轻松管理异步操作。
posted @ 2024-10-07 12:03  牛马chen  阅读(76)  评论(0编辑  收藏  举报