Jun 032011
 

I just want to share a quick tip for new parallel programmers. I have found that using a while(1) loop makes parallel code easier to write, read, and debug. This post just explains why I think its easier. In fact, I am also very curious if the experienced programmers agree with me or not.

Lets say I want to write a standard polling loop which runs until a certain condition is true. I have seen many reference books and notes on parallel programming write this loop as follows:

lock_acquire(lock);
while(check_condition()){
  lock_release(lock);
  //do any actual work in the iteration– Thanks to Caleb for this comment
  lock_acquire(lock);
}

lock_release(lock);

I dislike this code for two reasons. First, the lock_acquire is written after the lock_release which I find counter-intuitive. Second, it is more error prone because the lock_acquire and lock_release outside the loop are in fact a part of the loop. A less careful programmer can overlook either of the two which will make the code incorrect.

Now lets write it using a while(1):

while(1){
  bool condition_value;
  lock_acquire(lock);
    condition_value = check_condition();
  lock_release(lock);
  if(!check_condition)
    break;
  //do any actual work in the iteration– Thanks to Caleb for this comment
}

This code has two more lines but IMO it is easier to read and maintain. It is obvious where the critical section starts and finishes and the code is more structured.

What do you guys think?

  17 Responses to “Quick Tip: Why while(1) can make parallel code better?”

  1. I’m probably embarrassing myself here, but isn’t your preferred method the same as a do/while loop?

    • Yes, it is. Though not every language has a do-while construct.

      • Okay. Does the set of languages that lack the do-while construct contain any languages we might consider using in this scenario?

        • The language that immediately pops to mind is Go, a language whose goals include easy parallelization.

          • Interesting. Do you know the rationale for that design decision? Is it just to minimize syntax?

        • I’ve reached the comment nesting limit so I’m replying here.

          I don’t know the rationale, but one of the design goals of the language is simplified syntax, so I suspect that’s the primary reason.

    • Hi Caleb and Mark,

      Thanks for a great discussion. I realize my fault. Frankly, I did not intend for it to be a do-while but I totally see the source of confusion. In fact, the problem is that the definition of do-while is kind of kind of hazy here.

      Just for clarification: A do-while to me is a while loop which runs the loop body at least once even if its check_condition is false.Since my starting loop had an empty body, a while and do-while would have been exactly the same behavior.

      When I switched to the while(1), I took the condition_check and put it in the loop body. It does become a do-while because the new loop “body” will run at least once. However, one can also argue that what really constitutes the loop body is the condition_check() and the loop body is still empty because the loop isn’t doing any actual work except the condition_check().

      I think the while and do-while is something I should have watched out for when writing this post. Thanks for pointing it out.

      Just to clarify the point, I have now added some loop body (thanks to you). With the new comment, the loop is strictly a while in either case because the loop body never runs if check_condition is false.

      Thanks,
      Aater

  2. Comment nesting limit reached again.

    I have yet to really dive into Go myself, but I’ve seen several places that golang.org is the best place to start. This video gives a good introduction to the language.

    Go is still a new language, and the compilers don’t yet produce the most efficient code, but with the simplicity of the language, I expect it won’t take much work for it to become almost as fast as C.

    • Thanks a lot. It looks more C-ish than I expected. It seems to have pointers, does it?

      I guess I will learn more via reading.

      Btw, the web sandbox is pretty cool. I have thought of doing this for C but never found the time to do it.

  3. I don’t really like either example (though the while(1) is certainly an improvement). I would code it like this:

    bool locked_check_condition(lock) {
    lock_acquire(lock);
    bool result = check_condition();
    lock_release(lock);
    return result;
    }
    while(locked_check_condition(lock)){

    }

    • Hi Zach,

      That also a great of writing this code. It cleans up the outer loop a lot.

      May be its just a style thing but I prefer to write my lock acquire/release in the polling loops. The reason is that it makes it very obvious that there is a critical section in this loop. My usual concern is that it can lead to deadlocks because the programmer may not see the fact that there is a lock_acquire/release.

      Aater

  4. Hi Aater,

    Maybe I’m missing something, but it looks like in the first example, the lock is acquired and held while the work is done, but in the second version the lock is released before work is started.

    What is the lock protecting? Is it something check_condition accesses, something the “work” accesses or both?

    Regards,

    Billy

    • Hi Billy,

      Good catch! It wasn’t intentional. I added that comment solely to ref the confusion about the while vs. do-while without thinking about it too much.

      I apologize if it caused any confusion. I have fixed it so please let me know if anything else is required in your opinion.

      Regards,
      Aater

      • Thanks,

        I see now that the lock is protecting check_condition.

        In that case, I prefer Zach’s solution above. It is obvious what the lock is protecting, and the complexity of the locking is abstracted away from the loop, which becomes very simple and clear: “while check do work”.

        I’d try to avoid referencing the lock in the loop code if possible. Depending on the actual problem, you could argue that the code inside check_condition should know it needs to acquire the lock.

        Regards,

        Billy

  5. I just posted a blog entry about this:

    http://www.justsoftwaresolutions.co.uk/threading/simplify_code_by_encapsulating_locks.html

    and now I realise that Zach beat me to it in the comments above. Anyway, rather than replacing while(check_condition()) with while(1) and then testing the condition in the loop, it is better to encapsulate the lock with the condition check, as it simplifies the loop AND the locking.

  6. Wow, great article. Cool.

 Leave a Reply

(required)

(required)

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>