我可以将多个有序语句放入一个有序的 for 循环 (OpenMP) 中吗?

Can I put multiple ordered statements in one ordered for loop (OpenMP)?

我刚刚发现虽然这个 C 代码给出了一个有序的整数列表(如预期的那样):

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

int main() {
#pragma omp parallel for ordered schedule(dynamic)
  for (int i=0; i<10; i++) {
#pragma omp ordered
    {
    printf("%i             (tid=%i)\n",i,omp_get_thread_num(); fflush(stdout);
    }
  }
}

对于 gcc 和 icc,以下给出了不希望的行为:

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

int main() {
#pragma omp parallel for ordered schedule(dynamic)
  for (int i=0; i<10; i++) {
#pragma omp ordered
    {
    printf("%i             (tid=%i)\n",i,omp_get_thread_num()); fflush(stdout);
    }

    usleep(100*omp_get_thread_num());
    printf("WORK IS DONE  (tid=%i)\n",omp_get_thread_num()); fflush(stdout);
    usleep(100*omp_get_thread_num());

#pragma omp ordered
    {
    printf("  %i           (tid=%i)\n",i,omp_get_thread_num()); fflush(stdout);
    }
  }
} 

我希望看到的是:
0
1
2
3
4
5
6
7
8
9
工作完成
工作完成
工作完成
工作完成
工作完成
工作完成
工作完成
工作完成
工作完成
工作完成
0
1
2
3
4
5
6
7
8
9

但是 gcc 是 get:
0 (tid=5)
工作完成 (tid=5)
0 (tid=5)
1 (tid=2)
工作完成 (tid=2)
1 (tid=2)
2 (tid=0)
工作完成 (tid=0)
2 (tid=0)
3 (tid=6)
工作完成 (tid=6)
3 (tid=6)
4 (tid=7)
工作完成 (tid=7)
4 (tid=7)
5 (tid=3)
工作完成 (tid=3)
5 (tid=3)
6 (tid=4)
工作完成 (tid=4)
6 (tid=4)
7 (tid=1)
工作完成 (tid=1)
7 (tid=1)
8 (tid=5)
工作完成 (tid=5)
8 (tid=5)
9 (tid=2)
工作完成 (tid=2)
9 (tid=2)
(所以一切都有序 - 甚至是并行工作部分)

和 icc:
1 (tid=0)
2 (tid=5)
3 (tid=1)
4 (tid=2)
工作完成 (tid=1)
工作完成 (tid=3)
3 (tid=1)
6 (tid=4)
7 (tid=7)
8 (tid=1)
工作完成 (tid=0)
5 (tid=6)
工作完成 (tid=2)
1 (tid=0)
9 (tid=0)
工作完成 (tid=0)
工作完成 (tid=5)
工作完成 (tid=1)
9 (tid=0)
0 (tid=3)
8 (tid=1)
工作完成 (tid=4)
工作完成 (tid=6)
2 (tid=5)
工作完成 (tid=7)
6 (tid=4)
5 (tid=6)
4 (tid=2)
7 (tid=7)
(所以什么都没有订购,甚至连订购的条款都没有)

在一个有序循环中使用多个有序子句是未定义的行为还是这里发生了什么?在我能找到的任何 OpenMP 文档中,我找不到任何禁止每个循环使用多个子句的内容。

我知道在这个简单的例子中我可以像

int main() {  
  for (int i=0; i<10; i++) {  
    printf("%i             (tid=%i)\n",i,omp_get_thread_num()); fflush(stdout);  
  }  
#pragma omp parallel for schedule(dynamic)  
  for (int i=0; i<10; i++) {  
    usleep(100*omp_get_thread_num());  
    printf("WORK IS DONE  (tid=%i)\n",omp_get_thread_num()); fflush(stdout);  
    usleep(100*omp_get_thread_num());  
  }  
  for (int i=0; i<10; i++) {  
    printf("  %i           (tid=%i)\n",i,omp_get_thread_num()); fflush(stdout);  
  }          
}  

所以我不是在寻找解决方法。我真的很想了解这里发生了什么,这样我就可以处理真实情况而无需 运行 进入任何 devastating/unexpected.

我真的希望你能帮助我。

我对并行编程有点陌生,但我会尽力帮助你。

我修改了你的代码并测试了这个:

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

int main() {

  #pragma omp parallel num_threads(8)
  {

    #pragma omp for ordered schedule(dynamic)
    for (int i=0; i<10; i++) {

          #pragma omp ordered
          printf("%i (tid=%i) \n",i,omp_get_thread_num()); fflush(stdout);

    }

    printf("WORK IS DONE  (tid=%i)\n",omp_get_thread_num()); fflush(stdout);

  }


}

根据您用来编译机器的线程数调整您代码中的 examples.The 问题是访问 printf 指示工作已完成是随机完成的,每个线程都会执行此操作部分独立。在我的示例中,我让 for 循环的迭代按照有序子句状态执行,然后 for 子句隐式屏障让每个线程等待,直到所有线程都到达 for 循环和 for 之后的代码位置子句,然后每一个都打印出 "work is done"。如果您不使用 for 子句并且想要获得相同的输出,则可以使用显式屏障,换句话说,#pragma omp 屏障。

注意:"pragma omp parallel" 也使用隐式屏障,之后每个已创建的线程都会被销毁

这是我获得的可能输出:

0 (tid=7) 
1 (tid=5) 
2 (tid=0) 
3 (tid=4) 
4 (tid=1) 
5 (tid=3) 
6 (tid=2) 
7 (tid=7) 
8 (tid=5) 
9 (tid=0) 

WORK IS DONE  (tid=5)
WORK IS DONE  (tid=2)
WORK IS DONE  (tid=1)
WORK IS DONE  (tid=4)
WORK IS DONE  (tid=0)
WORK IS DONE  (tid=7)
WORK IS DONE  (tid=3)
WORK IS DONE  (tid=6)

如果这是您希望看到的那种输出,这是一种可能的实现方式。希望这会有所帮助,如有必要,请毫不犹豫地寻求进一步的帮助。继续编码!

根据 OpenMP 4.0 API specifications 你不能。

Only one ordered clause can appear on a loop directive (p. 58)