Thinking Parallel

A Blog on Parallel Programming and Concurrency by Michael Suess

Breaking Out of Loops in OpenMP

A Coaster LoopI have been quite late with my post this week, I apologize for that, but I have been sick with a cold (and I still am). Couple that with the fact that I did not find the time to write one or two posts in advance since Iwomp and you see why I am late this week. Hope my sickness does not influence my writing style too badly :grin:. Anyways. From time to time, readers write me their problems related to parallel programming. Especially with C++ and OpenMP. And while omp@openmp.org is probably the better place to ask those questions, I still try to help as much as I can and as much as my time permits, at least if its an interesting problem. The problem I would like to talk about today falls into this category for me, as it requires an interesting workaround: its the problem of how to throw an exception out of a parallel loop in OpenMP. Can’t do that, I hear you say? If you have read my past articles about exceptions and OpenMP you know that it is not trivial. But its doable with a little trick.

The code snippet my reader presented me with looked like this:

  1. int n(0);
  2.  
  3. #pragma omp parallel for
  4. for (int i = 0; i < 1000; ++i) {
  5.  
  6.     // Update progress
  7.     if (pCall->Aborted) {
  8.         throw abort_exception;
  9.     }
  10.    
  11.     #pragma omp critical(UpdateProgress)
  12.         pCall->Notify("Progress...", n * 100 / 1000);
  13.  
  14.     // Do something....
  15.        
  16.     #pragma omp critical(UpdateProgress)
  17.         ++n;
  18. } // end for

If the call to pCall->Aborted returns true, the user has canceled the current computation and every thread should stop working. Actually, we have not one problem here, but two:

  • We are not allowed to cancel work in a parallel region. I have had this problem so many times in the past that I have even worked on a proposal to solve it for my PhD. There is a publication available if you are interested in my solution. However, since it is quite big, requires changes in the compilers and I know you are not here to read my papers, I will show you the (much shorter) workaround instead.
  • We are not allowed to throw an exception out of a parallel region.

If you like to solve problems like this yourself, now is the time to stop reading and go craft a solution :grin:.

Got it? Since the workaround is not that complicated, I will restrain myself from keeping you away from it any longer, here it is:

  1. int n(0);
  2. bool abort = false;
  3.  
  4. #pragma omp parallel for
  5. for ( i=0; i<1000; ++i )
  6. {
  7.     #pragma omp flush (abort)
  8.     if (!abort) {
  9.  
  10.         //Update progress
  11.         if ( pCall->Aborted ) {
  12.             abort = true;
  13.             #pragma omp flush (abort)
  14.         }
  15.  
  16.         #pragma omp critical(UpdateProgress)
  17.         pCall->Notify("Progress...", n*100/1000);
  18.  
  19.         //Do something....
  20.  
  21.         #pragma omp critical(UpdateProgress)
  22.         ++n;
  23.     }
  24. }
  25.  
  26. if (abort)
  27. {
  28.     throw abort_exception;
  29. }

As you can see, the exception is no longer thrown from inside the parallel region, therefore the code is conforming OpenMP now. We also cannot break out of the for-loop directly, as the OpenMP-specification requires every loop iteration to be carried out. But using the branch on the abort-variable, we can make sure that as soon the user aborts the calculation, no useful work is being done anymore, therefore the calculation will finish really fast afterwards.

The last thing to mention here is the use of the explicit flush, which I usually don’t do anymore, because it is so error-prone. The use-case shown here (updating a boolean variable) is actually the only safe and portable way to use the explicit flush – a sad fact about OpenMP that warrants its own post (I have been meaning to post about the memory model for a looong time).

Hope you had some fun with todays episode of “find the workaround” :smile:!

9 Responses to Breaking Out of Loops in OpenMP »»


Comments

  1. Comment by Sanjiv Shah | 2007/06/30 at 16:20:47

    Hi Michael,

    This was called the “PDONE” directive in the original ASCI X3H5 specification, and the DONE directive in the original OpenMP 1.0 effort. The committee rejected it on the grounds that it was simple enough for the user to do, as you show above.

    Yes, we pushed for it, but there wasn’t enough support for it.

    Sanjiv

  2. Comment by Santiago | 2007/06/30 at 19:25:18

    Just an optimization… why instead of

    1. #pragma omp critical(UpdateProgress)
    2. ++n;

    you don’t do better

    1. #pragma omp atomic
    2. ++n;

    ???

  3. Comment by Michael Suess | 2007/07/01 at 21:16:07

    @Sanjiv: thanks for the clarification, maybe that decision should be revised some time in the future, as this is by far not the first time I encounter a problem that could be solved with a directive like that…

    @Santiago: I did not change that to atomic, because the original snippet used critical and (since its just a snippet) I cannot know if n is not modified elsewhere. Besides that, I only wanted to change as little as possible to get my point across. You are right, though, there is a good chance that atomic is the more optimal solution here…

  4. Comment by Carles (Spain) | 2010/11/01 at 19:14:57

    Thank you for this post! I’ve solve a problem with a for loop within a ‘return’ inside. Thanks!

  5. Comment by raghavg | 2012/01/17 at 14:23:44

    how to just resolve the part of “return 0″ thing inside open mp
    parallel region……….

  6. Comment by Shruthi | 2013/10/12 at 16:11:07

    hey i think there a simpler way of breaking out of the loop :
    what you need to do is make the for loop condition false so
    for( i=0 ; i<1000; ++i)
    {
    if (the abort condition here)
    {
    //you essentially want a break; statement here
    }
    }
    instead in the if block set i=1000; which will make the loop condition false and to avoid executing the rest of the loop use continue;

  7. Comment by Simon | 2014/08/13 at 15:33:30

    @Shruthi: Actually, that does not work the way you describe it. i is implicitly private and thus this will only break the loop for a single thread (maybe, since loops might be worked on in chunks and then even this thread might continue with the next chunk).
    Good news: OpenMP 4.0 will include omp cancel to break out of loops.


Trackbacks & Pingbacks »»

  1. […] just found this short but very helpful article on how to break an OpenMP parallel for loop. The key is the omp flush directive. Hopefully this […]

  2. […] this is the site i refer to, i used to follow their way : http://www.thinkingparallel.com/2007/06/29/breaking-out-of-loops-in-openmp/#reply […]

Leave a Reply

HTML allowed: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>