#pragma omp taskwait 与嵌套任务如何工作?

Fab*_*ang 3 parallel-processing openmp

我目前正在学习线程以及如何使用它们并行化代码。我们当前的主题是#pragma omp task。我目前的理解如下:

  1. 并行代码被执行
  2. 偶然发现 #pragma omp 任务
  3. 在任务池的范围内抛出代码
  4. 在作用域之后执行代码
  5. 不同的线程被分配taskt
  6. 在任务范围内执行的代码

假设您有以下代码

#pragma omp parallel {
  #pragma omp task // Task A 
  {...
    #pragma omp task // Task B 
    {...
    #pragma omp task // Task C 
      {...
      }
    #pragma omp taskwait
    }
  #pragma omp taskwait 
  }
}
Run Code Online (Sandbox Code Playgroud)

当任务 B 必须#pragma omp tastwait时,线程正在做什么?线程是否被迫等待任务 C 或者在等待任务 C 时可以执行其他任务?

我想还得等。我对任务的理解是否正确?

Jér*_*ard 5

首先,#pragma omp parallel是一个 fork-join 指令。这意味着每个线程都将执行该部分的内容,因此任务 A、B 和 C 被创建 N 次,其中 N 是线程数。您需要一个#pragma omp singleor#pragma omp master指令,以便为每种类型仅创建 1 个任务。

OpenMP 标准大多未指定任务的调度。基本上,该标准指定任务何时创建以及何时可以调度它们(调度点)调度如何受属性(如依赖关系)约束,但没有指定任务实际何时/如何进行。这是运行时的工作。事实上,主流运行时使用不同的调度策略。例如,IOMP 运行时 (Clang/ICC) 使用工作窃取方法,而 GOMP (GCC) 倾向于使用集中式调度程序(1 个大队列)。

#pragma omp taskwait适用于父级包含任务的当前上下文。这意味着第一个taskwait只等待任务C,第二个等待任务B。当一个线程等待一个任务时,它可以执行其他任务,因为taskwait指令是一个调度点。例如,IOMP 就是这样做的。这并不意味着确保执行其他任务。

您不应期望完成其他任务。当任务包含阻塞原语时,程序员通常会做出这种假设。这是一个坏主意,因为它通常在不可预测的时间内无缘无故地使用线程(OpenMP 运行时无法基于此优化其调度,因为它没有信息),而且还因为它可能导致死锁(由于任务依赖性)以及关于运行时的实现)。另请注意,taskyield 也不执行任务进展(不执行任何操作是 taskyield 的完全有效的实现)。

最后,它的工作原理如下。每个线程创建一个可以由其他线程执行的任务 A(这里不太可能)。当任务A执行时,它会为C创建另一个可以被其他线程执行的任务,以此类推。当第一个taskwait在线程中执行时,关联的父任务A和B被启动,C被创建并且可能有已经被处决了。同一线程可以启动任务 A、B 和 C,因为任务可以被中断(可能使用 continuation 。当执行taskwait时,保证当前B任务中创建的任务C完成(但其他任务的状态未定义)。