windows C++ 并行编程-PPL 中的取消操作(一)

并行模式库 (PPL) 中取消操作的角色、如何取消并行工作以及如何确定取消并行工作的时间。

运行时使用异常处理实现取消操作。 请勿在代码中捕捉或处理这些异常。 此外,还建议你在任务的函数体中编写异常安全的代码。 例如,可以使用获取资源即初始化 (RAII) 模式,以确保在任务体中引发异常时正确处理资源。 

要点
  • 取消是协作性的并且涉及在请求取消的代码和响应取消的任务之间的协作;
  • 如有可能,使用取消标记取消工作。 concurrency::cancellation_token 类定义了取消标记;
  • 当你使用取消标记时,请使用 concurrency::cancellation_token_source::cancel 方法初始化取消,并使用 concurrency::cancel_current_task 函数来响应取消。 使用 concurrency::cancellation_token::is_canceled 方法来检查任何其他任务是否已请求取消;
  • 取消不会立即发生。 如果任务或任务组已取消,即使新的工作未启动,活动的工作也必须检查和响应取消;
  • 基于值的延续继承前面的任务的取消标记。 基于任务的继续不会继承其前面的任务的标记;
  • 当你调用采用 cancellation_token 对象的构造函数或函数,但希望操作不可取消时,请使用 concurrency::cancellation_token::none 方法。 此外,如果没有将此取消标记传递给 concurrency::task 构造函数或 concurrency::create_task 函数,该任务是不可取消的;
并行工作树

PPL 使用任务和任务组来管理细化的任务和计算。 可以嵌套任务组,以形成并行工作树。 下图演示了并行工作树。 在该图中,tg1 和 tg2 表示任务组;t1、t2、t3、t4 和 t5 表示任务组执行的工作。

下面的示例演示了创建该图中的树所需的代码。 在此示例中,tg1 和 tg2 是 concurrency::structured_task_group 对象;t1、t2、t3、t4 和 t5 是 concurrency::task_handle 对象。

// task-tree.cpp
// compile with: /c /EHsc
#include <ppl.h>
#include <sstream>
#include <iostream>
#include <sstream>

using namespace concurrency;
using namespace std;

void create_task_tree()
{   
   // Create a task group that serves as the root of the tree.
   structured_task_group tg1;

   // Create a task that contains a nested task group.
   auto t1 = make_task([&] {
      structured_task_group tg2;
      
      // Create a child task.
      auto t4 = make_task([&] {
         // TODO: Perform work here.
      });

      // Create a child task.
      auto t5 = make_task([&] {
         // TODO: Perform work here.
      });

      // Run the child tasks and wait for them to finish.
      tg2.run(t4);
      tg2.run(t5);
      tg2.wait();
   });

   // Create a child task.
   auto t2 = make_task([&] {
      // TODO: Perform work here.
   });

   // Create a child task.
   auto t3 = make_task([&] {
      // TODO: Perform work here.
   });

   // Run the child tasks and wait for them to finish.
   tg1.run(t1);
   tg1.run(t2);
   tg1.run(t3);
   tg1.wait();   
}

还可以使用 concurrency::task_group 类创建类似的工作树。 concurrency::task 类还支持工作的树的概念。 但是,task 树是依赖关系树。 在 task 树中,将来的工作在当前工作之后完成。 在任务组树中,内部工作在外部工作之前完成。 有关任务和任务组之间的差异的详细信息,请参阅任务并行。

取消并行任务

可以通过多种方法来取消并行工作。 首选方法是使用取消标记。 任务组还支持 concurrency::task_group::cancel 方法和 concurrency::structured_task_group::cancel方法。 最后一种方法是在任务工作函数体中引发异常。 无论选择哪种方法,都应知道取消不会立即发生。 如果任务或任务组已取消,即使新的工作未启动,活动的工作也必须检查和响应取消。

取消标记和任务复合

concurrency::when_all 和 concurrency::when_any 函数可帮助你组合多个任务以实现常用模式。 本节描述这些函数如何与取消标记配合使用。

向任一 when_all 和 when_any 函数提供取消标记时,仅当该取消标记被取消,或者一个参与任务以已取消状态结束或引发异常时,该函数才会取消。

不向 when_all 函数提供取消标记时,该函数从组合成整体操作的每个任务继承取消标记。 当任意这些标记被取消,且至少有一个参与任务尚未启动或正在运行时,从 when_all 返回的任务被取消。 当一个任务引发异常时,将发生类似的行为,从 when_all 返回的任务因该异常被立即取消。

任务完成时,运行时会选择从 when_any 函数返回的任务的取消标记。 如果没有参与任务以已完成状态结束,并且一个或多个任务引发异常,则选择引发的一个任务来完成 when_any,并且其标记被选为结束任务的标记。 如果有多个任务以已完成状态结束,则从 when_any 任务返回的任务以已完成状态结束。 运行时尝试在完成时选取其标记未被取消的已完成任务,以便 when_any 不会被立即取消,则即使其他正在执行的任务可能在以后完成也是如此。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值