29

I know that you cannot have a break statement for an OpenMP loop, but I was wondering if there is any workaround while still the benefiting from parallelism. Basically I have 'for' loop, that loops through the elements of a large vector looking for one element that satisfies a certain condition. However there is only one element that will satisfy the condition so once that is found we can break out of the loop, Thanks in advance

for(int i = 0; i <= 100000; ++i)
  {
    if(element[i] ...)
     {
          ....
          break;
      }
   }
Tudor
  • 61,523
  • 12
  • 102
  • 142
Jeanno
  • 2,769
  • 4
  • 23
  • 31
  • 3
    related: [How to break out of a nested parallel (OpenMP) Fortran loop idiomatically?](http://stackoverflow.com/q/2979760/4279) – jfs Mar 20 '12 at 20:09

5 Answers5

34

See this snippet:

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;
    }
}

This situation is more suitable for pthread.

trooper
  • 4,444
  • 5
  • 32
  • 32
yyfn
  • 737
  • 4
  • 4
  • 1
    Q1 Why this this a continue rather than a break? Q2 Why is pthreads more suitable for this situation? Isn't openMP likely to be implemetned using pthreads on many platforms anyway? – Bruce Adams Nov 18 '19 at 12:12
  • To answer my own Q1 - break is not allow in openMP, all iteration s must be processed. The trick is that the remaining iterations no longer have any work to do and finish rapidly. See - https://software.intel.com/en-us/forums/intel-threading-building-blocks/topic/304882 and http://www.thinkingparallel.com/2007/06/29/breaking-out-of-loops-in-openmp/ – Bruce Adams Nov 18 '19 at 12:41
8

You could try to manually do what the openmp for loop does, using a while loop:

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++;
    }
}

This way you have to test "go" each cycle, but that should not matter that much. More important is that this would correspond to a "static" omp for loop, which is only useful if you can expect all iterations to take a similar amount of time. Otherwise, 3 threads may be already finished while one still has halfway to got...

Oak Bytes
  • 4,649
  • 4
  • 36
  • 53
Haatschii
  • 9,021
  • 10
  • 58
  • 95
  • Technically, you must read `go` atomically. Also the memory model guarantees no visibility unless you add `seq_cst` to both atomic operations. – Zulan Mar 29 '17 at 12:20
  • 1
    @Zulan, Correct, while there is not much danger in practice (except for some extra work done), the answer as is technically contains a data race. Nowadays (with C++11) I would definitely suggest using a `std::atomic` for `go`. I'll edit the answer accordingly. – Haatschii Mar 30 '17 at 16:24
2

I would probably do (copied a bit from 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;
      }
   }
}
enobayram
  • 4,650
  • 23
  • 36
0

Here is a simpler version of the accepted answer.

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;
        }
    }
}
Z boson
  • 32,619
  • 11
  • 123
  • 226
-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;
        }
    }
}
Peter Smartt
  • 358
  • 3
  • 11