According to this discussion on Stack Overflow, we should make a distinction between race conditions and data races. This blog post defines the terms and gives a neat example where the code is modified to exhibit zero, one or both behaviours.
Here’s an example of a race condition – the ordering of the execution affects the outcome (this can occur if one thread checks a value then performs an action, giving another thread the change to mutate the variable in between):
if (x == 5) // The "Check" { y = x * 2; // The "Act" // If another thread changed x in between "if (x == 5)" and "y = x * 2" above, // y will not be equal to 10. }
And here’s an example of a data race – a variable is mutated by multiple threads without synchronisation:
// Execute this function on five threads simultaneously for ( int i = 0; i < 10000; i++ ) { x = x + 1; }
In both cases, use of a synchronisation object across all the threads involved (e.g. a mutex) would address the issue.