CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Results 1 to 14 of 14
  1. #1
    Join Date
    Mar 2009
    Posts
    5

    consequences of race condition

    Hello everyone, I'm new here and would like your thoughts on the following 'code' snippet with two followup questions

    static int x=0;

    int main()
    {
    new thread1();

    while 1
    {
    inc();
    }
    }
    void thread1
    {
    while 1
    {
    inc();
    }
    }
    void inc()
    {
    if (++x%100 ==0)
    {
    printf("another +/- 100 ops x=%d", x);
    }
    sleep(0);
    }

    Am I right to expect that both threads may (from time to time) print the message for the same 100 operations?

    If the above is true, then perhaps x might be 500 when there have been 502 operations performed?

    The reason I am asking is because if the above are the only two consequences of the race condition then in this case, it's acceptable.

    Many Thanks.

  2. #2
    Join Date
    Nov 2003
    Posts
    1,902

    Re: consequences of race condition

    >> ... then in this case, it's acceptable.
    Just assume that anything can happen - including never seeing the printf. In other words, just toss out the idea of an "acceptable race condition".

    gg

  3. #3
    Join Date
    Mar 2001
    Posts
    2,529

    Re: consequences of race condition

    Well I suggest having a look at synchronization objects. Mutex, Critical section and semaphore are three methods that you can use to make sure your operations are threadsafe.
    ahoodin
    To keep the plot moving, that's why.

  4. #4
    Join Date
    Mar 2009
    Posts
    5

    Re: consequences of race condition

    Thank you for your replies.

    I have a good understanding of the system objects available to protect the counter variable above. This example comes from a larger system. Adding one line of code, would take months to rebuild, retest, redeploy.

    In a finite system such as computer programming, I am trying not to assume anything. I am trying to figure out if the above assuptions are the only possible influences on the counter variable (comment about printf statement noted).

    A colleague insists that at one time or another the variable could contain a "garbage" value. I tend to insist that the value x will always clearly reflect the number of operations performed - (minus) the number of times the race condition is hit.

    Anybody willing to take sides?
    Thanks
    ;-)
    Last edited by RwAA23; March 30th, 2009 at 04:39 AM. Reason: correction

  5. #5
    Join Date
    Nov 2003
    Posts
    1,902

    Re: consequences of race condition

    >> Anybody willing to take sides?
    The actual answer depends on the CPU architecture and the assembly instructions generated by the compiler (which could easily change with the change of a compiler option...).

    The general answer has been given. Anything can happen - meaning any value read from x can be considered "garbage".

    gg

  6. #6
    Arjay's Avatar
    Arjay is offline Moderator / EX MS MVP Power Poster
    Join Date
    Aug 2004
    Posts
    13,490

    Re: consequences of race condition

    As mentioned, the behavior is undefined which can certainly mean more than two predictable outcomes.

    Generally these sorts of bugs are difficult to track down and produce behavior that is completely unexpected (and usually isn't even close to the code where the bug occurred).

  7. #7
    Join Date
    Mar 2009
    Posts
    5

    Re: consequences of race condition

    Ok, thanks again for the posts. I get the feeling that I'm going wrong somewhere and if anybody has the patience to go back to basics to find out where, please let me know.

    I start with x=x+1 which (to me) means read x, add 1 to it, write x.

    For me, adding concurrency means that if a thread is interrupted between the read and the write, then both threads "think" they've incremented x; so you can never be sure that x is reflecting a correct value for whatever this program is doing; thus the need to protect access to it.

    What I am getting back on these posts is that there is a possibility to interrupt threads during the read and write operations, does this mean the value of x can be partially written while being read? That's what I am having a difficult time with.

    Or maybe another possibility, could some OS architectures require more than one operation to read or write; meaning that they can be interrupted between operations rather than during?

  8. #8
    Join Date
    Nov 2003
    Posts
    1,902

    Re: consequences of race condition

    >> does this mean the value of x can be partially written while being read?
    Possibly.

    >> require more than one operation to read or write; meaning that they can be interrupted between operations
    Possibly.

    There are many ways un-synchronized access to shared to shared memory can break your code:
    * re-ordering of program-order memory accesses by the compiler
    * re-ordering of inter-thread memory accesses by CPU cache-coherency and speculative execution algorithms of the HW
    * all the various interleavings of threads executing non-atomic instructions

    If you want to tell us the CPU, OS, and compiler you're using, then one could speculate as to what could actually occur when multiple threads execute "++x". In general it's a LOAD, INC, STORE - each of which may or may not be atomic.

    gg
    Last edited by Codeplug; March 31st, 2009 at 02:52 PM. Reason: un-synchronized

  9. #9
    Arjay's Avatar
    Arjay is offline Moderator / EX MS MVP Power Poster
    Join Date
    Aug 2004
    Posts
    13,490

    Re: consequences of race condition

    Rw, while it's good to get an understanding of what is going on an individual processor level, in the real world it's a bit dangerous to do so.

    IMO, it's better to learn how to perform synchronization in the general sense that can be applied to many different processor types.

    Of course, if you have specialized requirements, you may only need to ever code for a single processor.

  10. #10
    Join Date
    Mar 2009
    Posts
    5

    Re: consequences of race condition

    Codeplug, thanks for the post.

    For the value of x, I think I can put it to rest. Without synchro, the value can be anything at any given time.

    Arjay,

    Just one last question, could you briefly explain or give an example to what you eluded to in ticket 6? IS this relating to a "bad" value of x being passed further down the line and having a bug appear elsewhere? Or, is there some other black voodoo magic dangerous to the real world ;-) about having two thread both read and write to the same static memory location?

    Cheers

  11. #11
    Arjay's Avatar
    Arjay is offline Moderator / EX MS MVP Power Poster
    Join Date
    Aug 2004
    Posts
    13,490

    Re: consequences of race condition

    Quote Originally Posted by RwAA23 View Post
    Or, is there some other black voodoo magic dangerous to the real world ;-) about having two thread both read and write to the same static memory location?
    It's totally black voodoo magic. Either that or experience.

    In simple MT programs, race conditions can be tracked down relatively easily. An experience [mt] developer can usually spot the problems with a quick code inspection and may even be able to predict the type of failure(s).

    However, when the complexity of the system goes up, it becomes more difficult to understand or predict how or in what module the program will fail.

    Depending on the programmers style, it may be difficult to isolate these issues. For example consider a style where global variables are shared between threads (not an approach I recommend) in a complex program. If any unprotected access is made to the shared variable you will have unpredictable results which may manifest themselves in behaviors that aren't at all expected. Sure, when you track the issue down you can usually explain the behavior such that this unprotected global had a race condition that led to this, then this, and finally this. However, not always can the resultant behavior in complex systems be explained by immediately understanding that it's caused by an unprotected variable.

    As I said, I wouldn't recommend sharing a global variable between threads. I prefer to provide some isolation and encapsulation with data shared between threads. For example, I would create a class containing the data and create some synchronized accessors that read and write the data. The different threads that consume the class, don't need to worry about the synchronization chores - they simply call the accessors (and the synchronization happens within the class).

    Another synchronization approach that I follow is to use the RAII (Resource Aquisition Is Initialization). I use a couple of synch wrapper classes that wrap a critical section, mutex, and reader writer lock implementation and then a 'locker' class that provides the RAII support. The locker class provides the RAII by simply obtaining a lock in the ctor and automatically releasing it in the dtor. This ensures that a lock is always released and greatly simplifies the code.

    I mentioned earlier that I don't sweat knowing the atomic operations specific to a platform. The code I wrote isn't usually platform specific so I don't what to get into maintaining special cases as to whether I require synchronization on this platform or that. My general rule is that if I am sharing a variable across threads, then I synchronize access. The exceptioin to this is when the data in the variable is created prior to being accessed by the multiple threads and as a result is only ever read-only. Of course, part of getting good performance with regard to multithreading is to wisely choose the proper synch primitives (cs, mutex, etc.).

  12. #12
    Join Date
    May 2007
    Location
    Bangalore India
    Posts
    262

    Re: consequences of race condition

    >>Am I right to expect that both threads may (from time to time) print the >>message for the same 100 operations?

    Theoretically its possible that it may not print anything at all..

    Consider this scenario.

    (++x%100

    when x was just evaluating 99. Thread one kicks in and makes it 100, thats allright. But before it could do x%100, thread 2 kicks in and increase it to 101. Now ++x%100 will evaluate 1 and hence would not print.

    SO theoretically it may happen that it never print.
    Dont forget to rate my post if you find it useful.

  13. #13
    Join Date
    Mar 2009
    Posts
    5

    Re: consequences of race condition

    Thanks to everyone, I really enjoyed this discussion and I fully agree that failure to protect shared variables is normally bad form, sloppy and / or lazy. That can lead to "dangerous" situations since garbage values are not always expected nor are they handled safely. It is far better to avoid the garbage values rather than let them happen and have to defend against them later.

    I'll come clean. I started thinking about the consequences of this race condition as I was writting a quick program to diagnose something. The program had something like heartbeats, with a tolorance to miss one (or two in a row (which would have happened if the race condition was hit)). I knew it was a patch job, and couldn't be bothered adding sychronisation. Even adding one line of code with a "auto" critical section (similar to what Arjay explained with a lock & unlock in the ctor & dtor) add a dependancy to another class or library.

    Thanks again for the discussion, I wouldn't mind having you all over to my place sometime. I run a pretty tight ship. Heck you can almost eat off the floor. But I'll tell ya a little secret, I once left meatloaf in my fridge for over a month ;-)

  14. #14
    Lindley is offline Elite Member Power Poster
    Join Date
    Oct 2007
    Location
    Seattle, WA
    Posts
    10,895

    Re: consequences of race condition

    It should be pointed out that not all race conditions are capable of generating garbage, and not all race conditions are---strictly speaking---bad. But they're important to be aware of.

    Let's say that Event A and Event B occur in different threads. They access some of the same information, but are not strictly reliant on one or the other happening first. So long as that information is properly protected by a critical section, there's no danger of garbage being introduced. However, a race condition still exists; and if at some future point the ordering of A and B becomes relevant, this would need to be addressed.

Tags for this Thread

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  





Click Here to Expand Forum to Full Width

Featured