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_num();
    printf("%d | %d\n", tid, otid);
  }
}

int main(void) {
  omp_set_nested(0);
  #pragma omp parallel
  {
    foobar();
  }
  printf("\n");
  foobar();
  return 0;
}

期望这里发生的是 foobar() 上的并行区域和非并行调用都会吐出 4 行,与以下内容相符

// parallel region foobar()
0 | 0
1 | 1
2 | 2
3 | 3
// serial region foobar()
0 | 0
0 | 1
0 | 2
0 | 3

因为我不允许嵌套并行性。然而,我在并行区域内得到了 16 条具有正确 TID 的线,但 OTID 始终为 0(即每个线程都生成自己的 4 个线程,并在其上执行整个循环),并且在外部得到 4 条线(即并行区域)正如我所期望的,for 产生了 4 个线程)

我觉得我在这里遗漏了一些非常明显的东西,有人能为我提供一些线索吗?禁用嵌套不是应该将该 omp 并行 for 转换为常规 omp for 并相应地分配工作吗?

最佳答案

您的问题来自于 omp for 的错误假设指令将被解释,相应的工作将在线程之间分配,无论 parallel 是哪个区域处于事件状态。不幸的是,在您的代码中, omp for仅与parallel相关联函数 foobar() 中声明的区域。因此,当该区域被激活时(意味着由于您禁用了嵌套并行性,当 foobar() 未从另一个 parallel 区域调用时)您的循环将分布在新生成的线程中。但当它不是时,因为 foobar()从另一个 parallel 调用区域,然后 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;
}

我并不觉得这个解决方案完全令人满意,但我现在没有看到更好的解决方案。也许以后我会得到一些启发......

编辑:好吧,我有另一个想法:以相反的方式执行并强制嵌套并行性,每当从实际的 parallel 调用该函数时,只有一个事件线程。地区:

#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

关于c++ - OpenMP 嵌套未关闭,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59638111/

相关文章:

c++ - Matrix Native 类的迭代器

c++ - 编译Qt hello world程序时出现Undefined reference错误

c - 在 BST 中查找 sum=0 的三元组 - 使用以下代码的时间复杂度

c - Linux,读取磁带设备

c - SSE/AVX + OpenMP : fast sum of arrays

c++ - 共享内存线程和 MPI 之间的主要区别?

c++ - 有没有一种很好的方法来实现具有默认失败情况的条件类型?

c - clang <built-in> 头文件在哪里?

c - OpenMP并行的两种方法之间的区别

C++对指针: inconsistent segfault的引用