C++ OpenMP嵌套未关闭

C++ OpenMP嵌套未关闭,c++,c,openmp,C++,C,Openmp,我试图用OpenMP(4.5,通过GCC 7.2.0)管理嵌套的并行区域,但在关闭嵌套时遇到了一些问题 示例程序: #include <stdio.h> #include <omp.h> void foobar() { int tid = omp_get_thread_num(); #pragma omp parallel for for (int i = 0; i < 4; i++) { int otid = omp_get_thread_n

我试图用OpenMP(4.5,通过GCC 7.2.0)管理嵌套的并行区域,但在关闭嵌套时遇到了一些问题

示例程序:

#include <stdio.h>
#include <omp.h>

void foobar() {
  int tid = omp_get_thread_num();
  #pragma omp parallel for
  for (int i = 0; i < 4; i++) {
    int otid = omp_get_thread_num();
    printf("%d | %d\n", tid, otid);
  }
}

int main(void) {
  omp_set_nested(0);
  #pragma omp parallel
  {
    foobar();
  }
  printf("\n");
  foobar();
  return 0;
}
因为我不允许嵌套并行。但是,我在具有正确TID的并行区域内得到了16行,但OTID始终为0(即每个线程都生成了自己的4个线程,并在该线程上执行整个循环),而在外部得到了4行(即,正如我所期望的那样,并行for生成了4个线程)


我觉得我错过了一些很明显的东西,有人能帮我解释一下吗?禁用嵌套不应该将omp并行转换为常规omp for吗,并相应地分配工作?

您的问题来自错误的假设,即
omp for
指令将被解释,并且相应的工作将分布在线程之间,而不管哪个
parallel
区域处于活动状态。不幸的是,在您的代码中,的
omp仅与在函数
foobar()
中声明的
并行
区域相关联。因此,当该区域被激活时(这意味着由于您禁用了嵌套并行,当没有从另一个
并行
区域调用
foobar()
时),您的循环将分布在新生成的线程中。但如果不是,因为从另一个
parallel
区域调用
foobar()
,则忽略
omp for
,循环不会分布在调用线程之间。因此,它们中的每一个都执行整个循环,从而复制您看到的
printf()

一个可能的解决方案如下:

#include <stdio.h>
#include <omp.h>

void bar(int tid) {
  #pragma omp for
  for (int i = 0; i < 4; i++) {
    int otid = omp_get_thread_num();
    printf("%d | %d\n", tid, otid);
  }
}

void foobar() {
  int tid = omp_get_thread_num();
  int in_parallel = omp_in_parallel();
  if (!in_parallel) {
    #pragma omp parallel
    bar(tid);
  }
  else {
    bar(tid);
  }
}

int main() {
  #pragma omp parallel
  foobar();
  printf("\n");
  foobar();
  return 0;
}
这一次代码看起来更好,没有任何重复,并给出(例如):


问题不是描述你得到的输出,而是包括实际输出。不幸的是,这些解决方案在我的实际用例中不起作用。然而,这确实澄清了发生的事情。我想我误解了平行区域的动态范围是如何表现的。
#include <stdio.h>
#include <omp.h>

void bar(int tid) {
  #pragma omp for
  for (int i = 0; i < 4; i++) {
    int otid = omp_get_thread_num();
    printf("%d | %d\n", tid, otid);
  }
}

void foobar() {
  int tid = omp_get_thread_num();
  int in_parallel = omp_in_parallel();
  if (!in_parallel) {
    #pragma omp parallel
    bar(tid);
  }
  else {
    bar(tid);
  }
}

int main() {
  #pragma omp parallel
  foobar();
  printf("\n");
  foobar();
  return 0;
}
#include <stdio.h>
#include <omp.h>

void foobar() {
  int tid = omp_get_thread_num();
  omp_set_nested(1);
  #pragma omp single
  #pragma omp parallel for
  for (int i = 0; i < 4; i++) {
    int otid = omp_get_thread_num();
    printf("%d | %d\n", tid, otid);
  }
}

int main() {
  #pragma omp parallel
  foobar();
  printf("\n");
  foobar();
  return 0;
}
$ OMP_NUM_THREADS=4 ./nested
3 | 2
3 | 3
3 | 1
3 | 0

0 | 3
0 | 1
0 | 0
0 | 2