我正在尝试创建迭代进程的代码 ,同时将while保留在并行区域内以最小化并行化开销。
代码是这样的 问题是它永远不会退出,所以如果可能的话,我想了解你的想法
#include <stdio.h>
#include <omp.h>
int main(int argc, char **argv)
{
float error = 20;
#pragma omp parallel shared(error)
{
while (error > 5)
{
#pragma omp for reduction(-:error)
for (int i=0; i<10; ++i)
{
error -= 1;
}
}
}
fprintf(stderr, "Program terminated\n");
return 0;
}
答案 0 :(得分:1)
您可以通过在并行for循环之前插入障碍来使代码工作:
#pragma omp barrier
#pragma omp for reduction(-:error)
for(int i=0; i<10; ++i)
没有那个障碍并在2个线程上运行,一个线程将第二次进入for循环并将error
减少到5,而另一个线程根本不会进入第二个for循环,离开系统在一个奇怪的状态,一个线程执行并行for循环,但另一个线程拒绝加入。在使用它们作为其他地方的控制变量的并行循环和中写入共享变量肯定是一个警告。
答案 1 :(得分:0)
您的程序具有未指定的行为。请参见OpenMP 5.0 specification 1 中的第2.8节:
团队中的所有线程都必须遇到每个工作共享区域,或者根本不遇到任何
这意味着任何类型的分支(if
,while
等)其条件可能因#pragma omp for
(或其他任何分支)上的不同线程而不同其他 worksharing构造)是非法的:
#pragma omp parallel
{
if (...true for some threads, false for others...) // ILLEGAL!
{
#pragma omp for
for (...) ...
}
while (...true for some threads, false for others...) // ILLEGAL!
{
#pragma omp for
for (...) ...
}
}
对于您而言,这种未指定的行为可能导致以下事件序列:
while
循环,有些则不同。while
循环:
#pragma omp for
。error
。#pragma omp for
结尾处的隐式障碍处等待。while
循环:
#pragma omp parallel
结尾处的隐式障碍处等待。 OpenMP线程到达障碍时,它将等待,直到其团队中的所有线程都到达障碍。 #pragma omp for
的隐式屏障不适应遇到该构造的线程数。在您的情况下,某些线程永远不会在for
的末尾到达屏障循环(因为对他们来说while
条件为假)。他们跳过了while
循环,现在在#pragma omp parallel
末尾的隐式屏障处等待。
结果是陷入僵局:有些线程在#pragma omp for
的末尾等待,另一些线程在#pragma omp parallel
的末尾等待,而这两个组将再也无法在一起...
沃尔特答案中建议的#pragma omp for
之前的显式障碍通过分隔共享变量error
的读取和写入来解决此问题。更具体地说:
while
循环的主体。while
循环:
#pragma omp for
。error
。#pragma omp for
结尾处的隐式屏障处等待。
(屏障会执行隐式flush
,这意味着所有线程都将看到error
的最终值。)while
循环之后:
#pragma omp parallel
结尾处的隐式屏障处等待。当然,现在所有线程都执行for
循环,这并没有“最小化并行化开销”,这是您想要的。我猜您将不得不对代码进行一些重组才能实现该目标。也许使用#pragma omp task
代替#pragma omp for
是个好方法,但这取决于您实际数据结构和算法的细节。
注意:您可以通过在nowait
上添加#pragma omp for
子句来摆脱僵局,但这将是一个hack,并且您的程序仍将具有未指明的行为。
1:...或其他OpenMP版本中的相应部分。