Openmp并行部分与并行部分

bte*_*fik 4 c parallel-processing openmp

我有这两段代码

#pragma omp parallel
#pragma omp sections
  {
#pragma omp section
    printf("H");
#pragma omp section
    printf("e");
#pragma omp section
    printf("l");
#pragma omp section
    printf("l");
#pragma omp section
    printf("o");
#pragma omp section
    printf(" ");
#pragma omp section
    printf("W");
#pragma omp section
    printf("o");
#pragma omp section
    printf("r");
#pragma omp section
    printf("l");
#pragma omp section
    printf("d");
#pragma omp section
    printf("!");
  }
Run Code Online (Sandbox Code Playgroud)

char word[] = "Hello World!";
int n;

#pragma omp parallel for
  for(n=0; n<12; n++)
  {
  printf("%c", word[n]);
  }
Run Code Online (Sandbox Code Playgroud)

而第一个总是打印Hello World!第二个有时打印Hello World!,有时打印Helld!lo Wor

为什么第一个似乎是确定性的而另一个不是?

Hri*_*iev 7

首先,官方GCC 4.1.2 支持OpenMP.可能你有一个RedHat派生的Linux发行版(RHEL,Fedora,CentOS,Scientific Linux等),它的OpenMP支持从一些较新的版本向后移植到GCC 4.1.2中.RH用于维持该backport一段时间,直到他们最终切换到更新的GCC版本.

写入共享流会导致OpenMP部分和并行循环中的非确定性行为.您在此处观察到的是sectionsGCC中实现的动态调度性质的结果.libgomp(GCC OpenMP运行时)以先到先得的方式在团队中的线程之间分配部分.在您的情况下可能发生的情况是,部分的大小非常短,因此在执行时,在并行区域开头退出对接障碍的第一个线程会消耗所有工作项,然后其他线程甚至会赶上,结果连续执行所有部分.

而对于并行for循环,你看到的是默认循环调度的结果libgomp存在static,即12次迭代的线程之间以线性方式各占一半.我猜你的情况下有6个线程(基于来自加扰输出的文本段),因此线程0从0到1进行迭代,线程1从2到3进行迭代,依此类推.同样,每个线程中迭代的执行都得到了很好的定义,但是不能保证线程本身的执行顺序.

请注意,此行为非常符合GCC.OpenMP标准说:

在团队中的线程之间调度结构化块的方法是实现定义的.

例如,英特尔的编译器以循环方式分配这些部分,n即将部分赋予线程n % num_threads,就像for具有静态调度和块大小为1 的并行循环一样.