我有这两段代码
#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("!");
}
和
char word[] = "Hello World!";
int n;
#pragma omp parallel for
for(n=0; n<12; n++)
{
printf("%c", word[n]);
}
虽然第一个总是打印Hello World!
,但第二个有时打印Hello World!
,有时会打印Helld!lo Wor
为什么第一个似乎是确定性的而另一个不是?
答案 0 :(得分:7)
首先,官方GCC 4.1.2 不支持OpenMP。可能你有一个RedHat派生的Linux发行版(RHEL,Fedora,CentOS,Scientific Linux等),它的OpenMP支持从一些较新的版本向后移植到GCC 4.1.2中。 RH用于维持该backport很长一段时间,直到他们最终切换到更新的GCC版本。
写入共享流会导致OpenMP部分和并行循环中出现非确定性行为。您在此处观察到的是GCC中sections
实现的动态调度性质的结果。 libgomp
(GCC OpenMP运行时)以先到先得的方式在团队中的线程之间分配部分。在您的情况下可能发生的情况是,部分的大小非常短,因此在执行时,在并行区域开始处退出对接障碍的第一个线程会消耗所有工作项,然后其他线程甚至会赶上,结果连续执行所有部分。
对于并行for
循环,您观察到的是libgomp
中static
的默认循环调度的结果,即12个迭代均匀分配在线性时尚。我猜你的情况下有6个线程(基于来自加扰输出的文本段),因此线程0从0到1进行迭代,线程1从2到3进行迭代,依此类推。同样,每个线程中迭代的执行都得到了很好的定义,但是不能保证线程本身的执行顺序。
请注意,此行为非常符合GCC。 OpenMP标准说:
在团队中的线程之间调度结构化块的方法是 实施定义。
例如,英特尔的编译器以循环方式分发这些部分,即部分n
被赋予线程n % num_threads
,就像具有静态调度的并行for
循环一样。块大小为1。
答案 1 :(得分:4)
如果你想让for循环做同样的事情,请使用&#34; ordered&#34;在你的for循环中这样:
#pragma omp parallel for ordered
for(n=0; n<12; n++) {
#pragma omp ordered
printf("%c", word[n]);
}
查看此示例: http://bisqwit.iki.fi/story/howto/openmp/#ExampleCalculatingTheMandelbrotFractalInParallel
答案 2 :(得分:2)
omp parallel for
不具有确定性。您应该使用此子句来实现算法,这些算法在数组中具有独立数据。如果要打印一些文本,则字母应按顺序逐个跟随,但omp parallel for
以随机顺序执行代码。
答案 3 :(得分:2)