Ваша проблема связана с ложным предположением, что директива omp for
будет интерпретирована и соответствующая работа распределена между потоками независимо от того, какая область parallel
активна. К сожалению, в вашем коде omp for
связан только с регионом parallel
, который объявлен в функции foobar()
. Поэтому, когда этот регион активирован (то есть, поскольку вы отключили вложенный параллелизм, когда foobar()
не вызывается из другого parallel
региона), ваш l oop будет распределен среди вновь создаваемых потоков. Но если это не так, поскольку foobar()
вызывается из другого региона parallel
, то omp for
игнорируется, а l oop не распределяется между вызывающими потоками. Таким образом, каждый из них выполняет целое l oop, что приводит к репликации 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