使用带有break语句的OpenMP并行循环

29

我知道在OpenMP循环中不能使用break语句,但我想知道是否有任何解决方法,同时仍然能够从并行性中受益。基本上,我有一个'for'循环,它循环遍历一个大向量的元素,寻找满足特定条件的一个元素。然而只有一个元素会满足条件,因此一旦找到该元素,我们就可以退出循环。提前谢谢。

for(int i = 0; i <= 100000; ++i)
  {
    if(element[i] ...)
     {
          ....
          break;
      }
   }

3
如何在编写Fortran程序时优雅地打破嵌套并行循环(OpenMP)的惯用法? - jfs
5个回答

34

请看以下代码片段:

volatile bool flag=false;

#pragma omp parallel for shared(flag)
for(int i=0; i<=100000; ++i)
{    
    if(flag) continue;
    if(element[i] ...)
    {
          ...
          flag=true;
    }
}

这种情况更适合使用 pthread。


1
Q1 为什么这里使用 continue 而不是 break? Q2 为什么 pthreads 更适合这种情况?难道 openMP 不可能在许多平台上使用 pthreads 实现吗? - Bruce Adams
回答我的第一个问题 - 在openMP中不允许使用break,所有迭代都必须被处理。诀窍在于剩余的迭代不再有任何工作要做,并且会快速完成。请参见-https://software.intel.com/en-us/forums/intel-threading-building-blocks/topic/304882和http://www.thinkingparallel.com/2007/06/29/breaking-out-of-loops-in-openmp/。 - Bruce Adams

8

您可以尝试使用while循环手动完成openmp for循环的工作:

const int N = 100000;
std::atomic<bool> go(true);
uint give = 0;

#pragma omp parallel
{
    uint i, stop;

    #pragma omp critical
    {
        i = give;
        give += N/omp_get_num_threads();
        stop = give;

        if(omp_get_thread_num() == omp_get_num_threads()-1)
            stop = N;
    } 


    while(i < stop && go)
    {
        ...
        if(element[i]...)
        {
            go = false;
        }
        i++;
    }
}

这样,您需要在每个周期测试“go”,但这并不那么重要。更重要的是,这将对应于一个“静态”的omp for循环,仅当您可以预期所有迭代花费类似的时间时才有用。否则,3个线程可能已经完成,而另一个线程仍然完成一半...


从技术上讲,你必须以原子方式读取 go。此外,内存模型保证除非在两个原子操作中都添加了 seq_cst,否则不会有可见性。 - Zulan
1
@Zulan,正确,实际上没有太大的危险(除了一些额外的工作),但是答案在技术上包含数据竞争。现在(使用C++11),我肯定建议为go使用std::atomic<bool>。我会相应地编辑答案。 - Haatschii

2

我可能会做(从yyfn复制了一些)

volatile bool flag=false;

for(int j=0; j<=100 && !flag; ++j) {
  int base = 1000*j;
  #pragma omp parallel for shared(flag)
  for(int i = 0; i <= 1000; ++i)
  {

    if(flag) continue;
    if(element[i+base] ...)
     {
          ....
          flag=true;
      }
   }
}

0

这里是被接受答案的一个更简单的版本。

int ielement = -1;
#pragma omp parallel
{
    int i = omp_get_thread_num()*n/omp_get_num_threads();
    int stop = (omp_get_thread_num()+1)*n/omp_get_num_threads();        
    for(;i <stop && ielement<0; ++i){
        if(element[i]) {
            ielement = i;
        }
    }
}

-1
bool foundCondition = false;
#pragma omp parallel for
for(int i = 0; i <= 100000; i++)
{
    // We can't break out of a parallel for loop, so this is the next best thing.
    if (foundCondition == false && satisfiesComplicatedCondition(element[i]))
    {
        // This is definitely needed if more than one element could satisfy the
        // condition and you are looking for the first one.  Probably still a
        // good idea even if there can only be one.
        #pragma omp critical
        {
            // do something, store element[i], or whatever you need to do here
                ....

            foundCondition = true;
        }
    }
}

你真的认为将 boolfalse 进行比较是明智的吗? - Tomilov Anatoliy

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接