Home > Software engineering >  Race condition when increase a variable value in c
Race condition when increase a variable value in c

Time:04-03

I was asked this question in an interview recently. The question is if we have a function that takes a reference of int i as parameter and only does i . There is no any thread synchronizations. Now in main function, we initialize variable i with 0, then we create 7 new threads to run the same function and pass the same variable i, and after all threads are joined, how many possible values the variable i has? Thank you very much!

I tried thinking about the instructions of doing i . Like load, add and store instructions. Assume we’re using g compiler and in Linux OS.

CodePudding user response:

The code you describe has undefined behavior. The value of i is undefined. If you do compile and run the code and print i on the screen the output could be anything. It could be 42 or "hello world".

Perhaps the question was meant to tease you into considering how many different ways there are to have multiple threads increment i and how that could affect the output. However, when code has undefined behavior, then logical reasoning is futile.

On the other hand, if you care about what actually happens in the compiled code, then the only way to know that is to look at the compiler generated assembly. What the resulting program does is undefined, but it certainly does something. Though you can only know what that is after you compiled it and study the assembly. The C standard does not describe what such a program will do and whatever you get is not portable.

CodePudding user response:

As mentioned in other answers, there is UB.

Also, it is possible to have situations where this number isn't increased at all or incremented a few times (less than 7) or whatever else. Since it's not an atomic variable (the question didn't mention that) - it will yield very unstable/unpredictable results. See/google for "memory model" for more explainations.

CodePudding user response:

The specific instructions used to increment the variable depends on the instruction set, but unless using some kind of atomic increment, it will break down into load/add/store operations as you are describing.  On x86 that might be done with a single inc instruction, but without locking it will still break down to internal load/add/store operations.

You will want to look at the possible interleaving of those sequences.  The interleaving is caused by interruption of the non-atomic sequences.  Here is one possible such possible interleaving:

thread 1      thread 2
 load   
               load
               add
               store
 add
 store

That sequence will leave the variable incremented only once, by thread 1, because thread 2's increment operation is effectively ignored — thread 1 stores last so "wins".  (Thread 2 started with the wrong value in some sense anyway, so thread 2's store has the same value ( 1) as thread 1's store.)

So, on one extreme the answer would be that the variable will be incremented only by one.  On the other extreme, if each thread successfully increments without interruption of that sequence, then the variable would be incremented 7 times.  All intermediate values (incremented by 2-6) are also possible.


Since there is no synchronization at all, we also have to consider the possibility that we observe the original 0 after the joins, though I think this is unlikely due to the natural synchronization of system calls involved in creating threads and joining them.

  • Related