How understand the result of incrementing and printing a global variable by two threads?

Viewed 54

In my main I have two threads running the following function:

int i = 0;    

void foo()
{
   ++i;
   printf("%d", i);
}

I ran it 10000 times and I had 3 different results: {1 2}, {1 1}, {2 1}

First two I understand. The question is how the result can be {2 1} and why {2 2} doesn't appear at all.

Thank you!

1 Answers

To understand why any particular instance of undefined behavior happens to execute in a particular way on a particular machine, you usually have to read the assembly code generated by the compiler. Here is what gcc 10.2 on x86-64 produces. It does roughly the following:

  1. Load i from memory into a register
  2. Increment the register
  3. Store the register back to i
  4. Pass the contents of the register to printf.

So imagine that the threads happen to do those steps in the following order:

Thread A                  Thread B
--------                  --------
Step 1
Step 2
Step 3
                          Step 1
                          Step 2
                          Step 3
                          Step 4
Step 4

Then you can clearly see that the output will be 2 1.

As to why 2 2 never occurs, note that the value to be printed is loaded at step 1. One of the two threads must execute step 1 before the other, or at the same time. Thus at least one of them will load 0 at step 1, and therefore will print 1. Even if the other thread happens to have updated the value of i in memory before the first thread prints its value, it won't make any difference because the value to be printed is already in a register in the first thread.

(Of course it is entirely possible that some other compiler would generate code where i is reloaded from memory, and in that case 2 2 could occur. It just doesn't happen to be the case for this particular generated code.)

Related