C++ std::packaged_task 类

2025年3月21日 | 阅读 4 分钟

在本文中,我们将讨论 C++ 中的 std::packaged_task 类及其语法、参数、成员函数和示例。

C++ 中的 std::packaged_task 类是什么?

C++ 中,可调用对象,例如 函数、lambda 表达式、bind 表达式和任何其他函数对象,可以使用 std::packaged_task 类进行包装和异步运行。与某些其他 异步 执行技术(例如 std::async)不同,std::packaged_task 在创建时不会自动开始执行。相反,它会挂起,除非显式调用它。

调用 std::packaged_task 后,相应的可调用对象开始执行,并且计算的任何结果或异常都存储在共享状态中。如果在执行过程中出现错误,可以通过使用 std::future 对象检索结果来异步处理,该对象提供对该共享状态的访问。

语法

它具有以下语法:

参数

  • 模板: 以这种方式声明了两个模板参数和一个模板类。
  • R: R 表示与打包任务相关的函数的返回类型。
  • Args..: 名为 Args 的参数包表示与打包任务关联的函数接受的参数类型。Args 可以表示零个或多个模板参数,因为它是一个变参模板参数,如省略号 (...) 所示。
  • Packaged_task 类: 这是实际的类声明。它指示函数类型 R(Args...),其中 Args... 是表示参数类型的参数包,R 是返回类型,并定义了 packaged_task 类模板。

返回值

std::packaged_task 的返回值是一个对象,该对象表示与签名 R(Args...) 的可调用对象关联的任务。它允许任务的异步执行,并通过关联的 std::future 检索其结果。

考虑以下场景

考虑一个场景,其中现有函数负责从数据库 (DB) 检索并返回数据。假设此函数必须在单独的线程中执行,以防止阻塞主执行线程。

在这些情况下,std::packaged_task 是有益的。通过将数据库获取方法封装在打包任务中,我们可以在不同的线程上异步运行它,同时保证相关的 future 对象快速处理结果和任何潜在的异常。

成员函数

  • 运算符=: 这是为 std::packaged_task 重载的赋值运算符 (=)。它允许我们将一个 std::packaged_task 对象移动到另一个对象,从而转移其状态的所有权。
  • Swap: 此成员函数交换两个 std::packaged_task 对象的内容,它们交换其状态。它对于高效交换两个任务的状态很有用。
  • Get_future: 此成员函数返回与 std::packaged_task 的承诺结果关联的 std::future 对象。它允许我们异步检索结果或处理异常。
  • Reset: 此成员函数重置 std::packaged_task 对象。它清除与任务关联的任何状态,使其可以重用。
  • 构造函数: 构造函数初始化 std::packaged_task 对象,通常将可调用对象作为参数。
  • 析构函数: 当 std::packaged_task 对象超出范围时,析构函数解除分配与该对象关联的资源。

示例

让我们举一个例子来说明 C++ 中的 std::packaged_task

输出

 
The sum of the vector elements: 184   

说明

  • 此示例演示了 std::packaged_task 用于异步函数执行。SumVector 函数使用 std::accumulate 确定向量中元素的总和。
  • 在创建并初始化名为 nums 的向量后,使用整数。
  • SumVector 方法用于创建名为 task 的 std::packaged_task。
  • 之后,任务生成相关的 std::future 对象 future,该对象将存储异步计算的结果。
  • 使用 std::move(task) 函数,将向量 nums 作为参数传入,导致任务在不同的线程“t”中异步运行。
  • 使用 t.join() 方法,主线程等待异步任务完成。
  • get() 方法用于接收结果,该结果包含执行操作后向量元素的总和。结果打印在控制台上。