OpenMP 任务循环:两个连续任务循环构造之间的同步

OpenMP taskloop: synchronization between two consecutive taskloop constructs

两个 taskloop 构造之间的同步是如何完成的?具体来说,在下面的伪代码中,如果可用线程数多于第一个循环的任务数,我相信这些空闲线程在单个构造结束时的隐式屏障处旋转。现在是否允许这些空闲线程同时开始执行第二个循环,从而使以这种方式并行化事物变得不安全(由于数组 A 的相互依赖性)?

!$omp parallel
!$omp single

!$omp taskloop num_tasks(10)
DO i=1, 10
    A(i) = foo()
END DO
!$omp end taskloop

!do other stuff

!$omp taskloop
DO j=1, 10
    B(j) = A(j)
END DO
!$omp end taskloop

!$omp end single
!$omp end parallel

我没能从API规范中找到明确的答案:https://www.openmp.org/spec-html/5.0/openmpsu47.html#x71-2080002.10.2

默认情况下,taskloop 结构周围有一个隐式的 taskgroup。考虑到这一点,您的代码发生的情况是 single 构造从并行团队的可用线程中挑选任何一个线程(我将其称为生产者线程)。然后将 n-1 个其他线程直接发送到 single 构造的屏障,并等待工作(任务)到达。

现在 taskgroup 发生的事情是生产者线程开始创建循环任务,然后在 taskloop 构造结束时等待所有创建的任务完成:

!$omp parallel
!$omp single

!$omp taskloop num_tasks(10)
DO i=1, 10
    A(i) = foo()
END DO
!$omp end taskloop  ! producer waits here for all loop tasks to finish

!do other stuff

!$omp taskloop
DO j=1, 10
    B(j) = A(j)
END DO
!$omp end taskloop ! producer waits here for all loop tasks to finish

!$omp end single
!$omp end parallel

因此,如果您的并行度(= 第一个 taskloop 创建的任务数)少于屏障中的 n-1 个工作线程,那么其中一些线程将空闲。

如果你想要更多的重叠并且如果“其他东西”独立于第一个taskloop,那么你可以这样做:

!$omp parallel
!$omp single


!$omp taskgroup
!$omp taskloop num_tasks(10) nogroup
DO i=1, 10
    A(i) = foo()
END DO
!$omp end taskloop  ! producer will not wait for the loop tasks to complete

!do other stuff

!$omp end taskgroup ! wait for the loop tasks (and their descendant tasks)

!$omp taskloop
DO j=1, 10
    B(j) = A(j)
END DO
!$omp end taskloop

!$omp end single
!$omp end parallel

唉,5.1 版的 OpenMP API 不支持 taskloop 构造的任务依赖性,因此您无法轻松描述第一个 taskloop 和第二个循环迭代之间的依赖性taskloop。 OpenMP 语言委员会目前正在处理这个问题,但我没有看到它在 OpenMP API 5.2 版中实现,而是在 6.0 版中实现。

PS(编辑):对于第二个 taskloop,因为它就在 single 构造结束之前,因此就在障碍之前,您可以轻松添加 nogroup 也可以避免等待生产者线程的额外时间。