部分和任务openmp之间的区别

OpenMP之间有什么区别:

#pragma omp parallel sections { #pragma omp section { fct1(); } #pragma omp section { fct2(); } } 

和:

 #pragma omp parallel { #pragma omp single { #pragma omp task fct1(); #pragma omp task fct2(); } } 

我不确定第二个代码是否正确

任务和部分之间的区别在于代码执行的时间范围内。 部分包含在sections结构中,并且(除非指定了nowait子句)线程将不会离开它直到所有部分都被执行完毕:

  [ sections ] Thread 0: -------< section 1 >---->*------ Thread 1: -------< section 2 >*------ Thread 2: ------------------------>*------ ... * Thread N-1: ---------------------->*------ 

这里有N线程会遇到一个由两部分组成的部分,第二部分比第一部分花费更多的时间。 前两个线程分别执行一个部分。 其他的N-2线程简单地等待在部分结构的末尾的隐式屏障(在这里显示为* )。

任务在所谓的任务调度点上尽可能排队并执行。 在某些情况下,运行时间可以被允许在线程之间移动任务,即使在他们的生命周期中。 这样的任务被称为解开,一个解开的任务可能开始在一个线程中执行,然后在某个调度点,它可能被运行时迁移到另一个线程。

不过,任务和部分在很多方面都是相似的。 例如,以下两个代码片段实现了基本相同的结果:

 // sections ... #pragma omp sections { #pragma omp section foo(); #pragma omp section bar(); } ... // tasks ... #pragma omp single nowait { #pragma omp task foo(); #pragma omp task bar(); } #pragma omp taskwait ... 

taskwait工作非常像barrier但任务 – 它确保当前的执行stream程将暂停,直到所有排队的任务已经执行。 这是一个调度点,即它允许线程处理任务。 single构造是必需的,因此任务将仅由一个线程创build。 如果没有single构造,每个任务都会创buildnum_threads次,这可能不是我们想要的。 single构造中的nowait子句指示其他线程不要等到single构造被执行(即去除single构造末端的隐式障碍)。 所以他们马上taskwait任务,开始处理任务。

为了清楚起见, taskwait是一个明确的调度点。 还有隐含的调度点,最显着的是在屏障同步内部,无论是显式的还是隐式的。 因此,上面的代码也可以写成:

 // tasks ... #pragma omp single { #pragma omp task foo(); #pragma omp task bar(); } ... 

如果有三个线程,可能会发生以下情况:

  +--+-->[ task queue ]--+ | | | | | +-----------+ | | | Thread 0: --< single >-| v |----- Thread 1: -------->|< foo() >|----- Thread 2: -------->|< bar() >|----- 

在这里显示| ... | | ... | 是调度点的行为( taskwait指令或隐式屏障)。 基本上,线程12挂起了他们正在做的事情,并开始处理队列中的任务。 一旦所有任务都被处理完毕,线程恢复正常的执行stream程。 请注意,线程12可能在线程0退出single构造之前到达调度点,因此左边的| 不需要alignment(这在上面的图表中表示)。

可能还会发生线程1能够完成处理foo()任务并在其他线程能够请求任务之前请求另一个任务。 所以foo()bar()可能被同一个线程执行:

  +--+-->[ task queue ]--+ | | | | | +------------+ | | | Thread 0: --< single >-| v |--- Thread 1: --------->|< foo() >< bar() >|--- Thread 2: --------------------->| |--- 

如果线程2来得太晚,单挑线程也可能执行第二个任务:

  +--+-->[ task queue ]--+ | | | | | +------------+ | | | Thread 0: --< single >-| v < bar() >|--- Thread 1: --------->|< foo() > |--- Thread 2: ----------------->| |--- 

在某些情况下,编译器或OpenMP运行时甚至可能完全绕过任务队列并连续执行任务:

 Thread 0: --< single: foo(); bar() >*--- Thread 1: ------------------------->*--- Thread 2: ------------------------->*--- 

如果区域代码内没有任务调度点,那么OpenMP运行时可能会在合适的时候启动任务。 例如,有可能所有的任务都被推迟到达到parallel区域末尾的障碍。