In an OpenMP code, how might one break out of a parallel loop after some condition is met? With a serial code, the ordinary way to do this is with a while loop. However, basic OpenMP seemingly offers only parallel for loops, in which statements like "break" are disallowed. Is this type of functionality, therefore totally missing from the standard?

The answer is no—but to implement a parallel while loop in OpenMP, some work is required. One way to do it is to make use of the task< directive introduced in OpenMP 3.0, which is well suited for irregular parallelism of this kind. However, as the following extended C code example shows, the same goal can also be achieved through a combination of the basic directives that we have covered so far.

Our example draws upon all facets of OpenMP that have been described in this roadmap. It consists of a parallel construct with shared and private variables. A couple of control directives (critical, flush) play important roles. There are calls to the OpenMP runtime libraries. Take some time to read both the code and the comments to understand how the elements all work together. Then, you might want to copy and paste the code into a Stampede2 window (try cat > while_omp.c and then pasting the code below into the terminal; use Ctrl-D to exit) and compile and run it to see what happens! (Hint: remember to compile with icc -qopenmp.)


#include <omp.h>
#include <stdio.h>
#include <unistd.h>
int main(int argc, char **argv)
{
  /* OpenMP does not provide a parallel while loop,
     so we're going to have to make one ourselves... */
  int sj, sstop, tn, tj, tstop;
  int foo(int j);
  omp_set_num_threads(8);

  /* Start carefully - we don't want all threads
     to (re!)initialize the two shared variables */
  sj = -1;     // shared loop counter
  sstop = 0;   // shared stopping condition

  #pragma omp parallel private(tn,tj,tstop)
  {
    tn = omp_get_thread_num();
    while (!sstop)
    {
      /* Threads update the shared counter by turns */
      #pragma omp critical
      {
        sj++;      // increment the shared loop counter...
        tj = sj;   // ...and keep a private copy of it
      }
      /* Threads evaulate function foo in parallel */
      tstop = foo(tj);

      /* Flip sstop for everyone if tstop is true in a thread;
         flush to make all threads both release and acquire it */
      if (tstop == 1) sstop = 1;
      #pragma omp flush(sstop)

      /* Threads could be anywhere in the loop when sstop = 1;
         they must all proceed to the loop's end before exiting */
      printf("Thread %d, iteration %d, sstop=%d\n",tn,tj,sstop);
    }
  }
}
int foo(int j)
{
  /* This function simply compares counter j to its limit -
     a real code would likely do something more interesting  */
  int jmax=23, condition;
  condition = (j == jmax);
  usleep(100000);   // usleep stands in for real work
  return condition;
}

 
©   Cornell University  |  Center for Advanced Computing  |  Copyright Statement  |  Inclusivity Statement