2

My problem is that when reading about threads it came up that if multiple treads accesses a variable a race-condition would happen. My intuition is that my code would create a race-condition for "int a" in this case like this https://en.wikipedia.org/wiki/Race_condition#Example but it does not happen. My question is why is that so?

I have tried to create multiple threads in a array and individually but the race-condition does not happen.

void increment(int& a) {
    ++a;
}

int main()
{

    int a = 0;

    std::thread pool[100];

    for (auto& t : pool) {
        t = std::thread(increment, std::ref(a));
    }


    for (auto& t : pool) {
        t.join();
    }

    printf("%d", a);

}

I expect that only some threads actually increases "a" and that a race-condition happens, but that is not the case with my code

Jens
  • 89
  • 2
  • 6
  • 8
    The fun thing about undefined behavior is that the correct result is in the set of results you can have. – NathanOliver Aug 23 '19 at 17:45
  • 2
    How did you conclude that there is no race condition? – HolyBlackCat Aug 23 '19 at 17:45
  • 1
    https://stackoverflow.com/questions/39393850/can-num-be-atomic-for-int-num – Evg Aug 23 '19 at 17:46
  • Related, if not a dupe: https://stackoverflow.com/questions/57603868/is-a-comparison-on-monotonic-count-integer-safe/57603952#57603952 – πάντα ῥεῖ Aug 23 '19 at 17:47
  • It should also be noted that the compiler might not even generate instructions exactly like the example you're comparing to on Wikipedia, so you shouldn't be looking for just `a == 1` to detect a race. You *are* seeing a race condition even if `a == 2`; How do you know which thread incremented `a` first? – Romen Aug 23 '19 at 17:59
  • There is no race condition until there is a race condition. – PaulMcKenzie Aug 23 '19 at 19:18

3 Answers3

8

It does.

You just haven't witnessed any symptoms of it yet, due to pure chance.

(I expect that creating and storing those threads one at a time is much slower than the increment itself, so by the time you're onto the next thread the increment from the last one is usually done already. But you can't guarantee this, which is a classic race condition.)

You should/must increment a atomically, or synchronise it with a mutex.

Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
6

This is a perfect example of unlucky undefined behavior.

It just fools with the result you expect, and you never know when and where it will hit you in face.

To prevent it you either have to use atomics or use a mutex

Oblivion
  • 7,176
  • 2
  • 14
  • 33
0

You can add debug message to print the thread number and value of a in increment function. If increment is in order of thread number then there is no race condition.

Also another point: what do you expect in race condition, this piece of just increments the value of a memory location. It is not a database which will result in dead lock condition

  • _"If increment is in order of thread number then there is no race condition."_ No, this is just another race condition. You must not rely on such results. – Lightness Races in Orbit Aug 24 '19 at 00:19
  • _"what do you expect in race condition, this piece of just increments the value of a memory location. It is not a database which will result in dead lock condition"_ Again, incorrect. You do not appear to hold an understanding of how these operations work. The increment is not atomic. There is _already_ a race condition, right there, in this simple program. – Lightness Races in Orbit Aug 24 '19 at 00:19