2 回答
首先,#pragma omp simple
OpenMP 4.5 规范中没有。我假设你的意思是#pragma omp single
.
如果是这样,那么在区域pragma omp barrier
内是一个坏主意single
,因为只有一个线程将执行代码并等待所有其他线程,这些线程不执行该区域。
此外,在 A2、B2 和 C2 的第二个中,不再作为任务并行执行。
对于您的尖锐问题:您正在寻找的似乎是OpenMP Secification pgdepend
中 Task 构造的子句。169 .
Massimiliano对这个问题的依赖子句以及它是如何工作的有一个很好的解释。
一旦您了解了那里发生的事情,最后一个示例就没有那么复杂了:每个任务都Tn
依赖于前一次迭代T-1_n
及其邻居(T-1_n-1
和T-1_n+1
)。这种模式被称为Jacobi 模板。它在偏微分方程求解器中很常见。
正如 Henkersmann 所说,最简单的选择是使用 OpenMP Task 的depend
子句:
int val_a[N], val_b[N];
#pragma omp parallel
#pragma omp single
{
int *a = val_a;
int *b = val_b;
for( int t = 0; t < T; ++t ) {
// Unroll the inner loop for the boundary cases
#pragma omp task depend(in:a[0], a[1]) depend(out:b[0])
stencil(b, a, i);
for( int i = 1; i < N-1; ++i ) {
#pragma omp task depend(in:a[i-1],a[i],a[i+1]) \
depend(out:b[i])
stencil(b, a, i);
}
#pragma omp task depend(in:a[N-2],a[N-1]) depend(out:b[N-1])
stencil(b, a, N-1);
// Swap the pointers for the next iteration
int *tmp = a;
a = b;
b = tmp;
}
#pragma omp taskwait
}
如您所见,OpenMP 任务依赖是点对点的,这意味着您不能用数组区域来表达它们。
对于这种特定情况,另一种选择更简洁,是使用屏障间接强制依赖:
int a[N], b[N];
#pragma omp parallel
for( int t = 0; t < T; ++t ) {
#pragma omp for
for( int i = 0; i < N-1; ++i ) {
stencil(b, a, i);
}
}
每次内循环完成时,第二种情况都会执行同步屏障。同步粒度更粗,因为每次外循环迭代只有 1 个同步点。但是,如果stencil
函数很长且不平衡,则可能值得使用任务。