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



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

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

假设您有以下代码

#pragma omp parallel {
#pragma omp task // Task A 
{...
#pragma omp task // Task B 
{...
#pragma omp task // Task C 
{...
}
#pragma omp taskwait
}
#pragma omp taskwait 
}
}

当线程必须#pragma omp tastwait时,线程正在执行任务B。?线程是否强制等待任务C,或者在等待任务C时可以执行其他任务?

我认为它必须等待。我对任务的理解正确吗?

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

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

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

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

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

最新更新