Fab*_*ang 3 parallel-processing openmp
我目前正在学习线程以及如何使用它们并行化代码。我们当前的主题是#pragma omp task。我目前的理解如下:
假设您有以下代码
#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 时可以执行其他任务?
我想还得等。我对任务的理解是否正确?
首先,#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完成(但其他任务的状态未定义)。