当杂注内部有编译指示时,OpenMP 中会发生什么?

What happens in OpenMP when there's a pragma for inside a pragma for?

本文关键字:OpenMP 什么 内部 指示 编译      更新时间:2023-10-16

#pragma omp parallel开始时创建了一堆线程,然后当我们到达#pragma omp for时分配工作负载。如果这个for循环里面有一个for循环,并且我在它前面也放了一个#pragma omp for,会发生什么?每个线程都创建新线程吗?如果没有,分配给哪些线程这个任务?在这种情况下到底会发生什么?

默认情况下,不为内部循环生成线程。它是通过到达它的线程顺序完成的。

这是因为嵌套在默认情况下是禁用的。但是,如果您通过omp_set_nested()启用嵌套,那么将生成一组新的线程。

然而,如果你不小心,这将导致p^2的线程数(因为每个原始的p线程将产生另一个p线程)。因此,默认情况下,嵌套是禁用的。

在如下情况下:

#pragma omp parallel
{
#pragma omp for
  for(int ii = 0; ii < n; ii++) {
    /* ... */
#pragma omp for 
    for(int jj = 0; jj < m; jj++) {
      /* ... */
    }
  }
}

当您违反OpenMP标准时,会触发未定义的行为。更准确地说,你违反了第2.5节(工作共享结构)中的限制:

以下限制适用于工作共享结构:

  • 每个工作共享区域必须被团队中的所有线程遇到,或者根本没有线程遇到。
  • 对于团队中的每个线程,遇到的工作共享区域和屏障区域的顺序必须相同。
a . 39.c和A.40.1c的例子清楚地说明了这一点:

示例a . 39.c :下面的循环构造嵌套的示例符合,因为内部和外部循环区域绑定到不同的并行区域:

void work(int i, int j) {}
void good_nesting(int n)
{
  int i, j;
#pragma omp parallel default(shared)
  {
#pragma omp for
    for (i=0; i<n; i++) {
#pragma omp parallel shared(i, n)
    {
#pragma omp for
      for (j=0; j < n; j++)
        work(i, j);
    }
    }
  }
}

示例A.40.1c:以下示例不符合,因为内环和外环区域紧密嵌套

void work(int i, int j) {}
void wrong1(int n)
{
#pragma omp parallel default(shared)
  {
    int i, j;
#pragma omp for
    for (i=0; i<n; i++) {
    /* incorrect nesting of loop regions */
#pragma omp for
      for (j=0; j<n; j++)
        work(i, j);
    }
  }    
}

注意这与:

不同
#pragma omp parallel for
  for(int ii = 0; ii < n; ii++) {
    /* ... */
#pragma omp parallel for 
    for(int jj = 0; jj < m; jj++) {
      /* ... */
    }
  }

,尝试在其中生成嵌套的并行区域。