簡體   English   中英

OpenMP 嵌套未關閉

[英]OpenMP nesting not turning off

我正在嘗試使用 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

因為我不允許嵌套並行。 但是,我在具有正確 TID 的並行區域內得到 16 行,但 OTID 始終為 0(即每個線程都產生 4 個自己的線程,並在其上執行整個循環)並且我在外部得到 4 行(即並行因為正如我所期望的那樣產生 4 個線程)

我覺得我在這里遺漏了一些非常明顯的東西,有人能幫我解釋一下嗎? 是否禁用嵌套應該將該 omp 並行轉換為常規 omp for,並相應地分配工作?

您的問題來自錯誤的假設,即omp for指令將被解釋並且相應的工作分布在線程之間,而不管哪個parallel區域處於活動狀態。 不幸的是,在您的代碼中, omp for僅與函數foobar()聲明的parallel區域相關聯。 因此,當這個區域被激活時(意思是因為你禁用了嵌套的並行性,當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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM