#14: Data Race vs. Race Condition
Hello! Can you clearly explain the differences between data races and race conditions?
If we want to write effective concurrent code, understanding the difference between a data race and a race condition is crucial for us as developers.
A data race occurs when two or more threads simultaneously access the same memory location, and at least one of these accesses is a write operation.
A race condition refers to any situation where the outcome depends on the timing of events that can’t be controlled, such as which thread runs first.
Consider the following code:
// Thread 1 code
coffee.price = 10
// Thread 2 code
print(coffee.price)
If the two threads can run concurrently and we can’t control which thread executes first, this code produces a data race. Indeed, thread 1 writes to the price
variable, whereas thread 2 reads it. The value printed by thread 2 is unpredictable—it could be 10 if thread 1 executes first or the initial price if thread 1 executes afterward.
Data races can result in corrupted data, system instability, and are often a source of subtle and hard-to-track bugs. To avoid these, we should use synchronisation mechanisms. For example, with a mutex:
// Thread 1 code
mutex.Lock()
coffee.price = 10
mutex.Unlock()
// Thread 2 code
mutex.Lock()
print(coffee.price)
mutex.Unlock()
This code resolves the data race by using a mutex to ensure that only one thread accesses price
at a time. Yet, is the outcome deterministic? Still not. Depending on which thread executes first, thread 2 will still print different results. In this example, we can’t control the sequence between thread 1 and thread 2; therefore, it’s a race condition.
Not all race conditions are problematic. For example, a Twitter post showing 605 likes instead of 606 for a few seconds is a harmless race condition. However, if our bank application shows an outdated account balance after a transaction, that’s more impactful.
All data races are race conditions, yet not all the race conditions are data races. It’s important to understand that a data-race-free application doesn’t necessarily guarantee deterministic results. Indeed, an application can be free of data races but still exhibit race conditions due to factors like thread execution order or database call durations.
Tomorrow, you will receive your weekly recap on the concurrency theme.