我正在尝试使用 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/