What is race condition ?

Denny Lesmana
4 min readJun 9, 2023

--

A Race Conditions In Distributed Or Multithreaded System generally occurs when there are multiple threads or clients trying to access the same resource at one point of time resulting in an inconsistent, unavailable and faulty behaviour.

In programming, two main types of race conditions occur in a critical section of code, which is a section of code executed by multiple threads. When multiple threads try to read a variable and then each acts on it, one of the following situations can occur:

  • Read-modify-write. This kind of race condition happens when two processes read a value in a program and write back a new value. It often causes a software bug. Like the example above, the expectation is that the two processes will happen sequentially — the first process produces its value and then the second process reads that value and returns a different one.
    For example, if checks against a checking account are processed sequentially, the system will make sure there are enough funds in the account to process check A first and then look again to see if there are enough funds to process check B after processing check A. However, if the two checks are processed at the same time, the system may read the same account balance value for both processes and give an incorrect account balance value, causing the account to be overdrawn.
See how a race condition could develop if a bank receives two checks — one for $1,000 and the other for $1,500 — at about the same time, both drawn against a checking account with only $2,000 in it.
  • Check-then-act. This race condition happens when two processes check a value on which they will take each take an external action. The processes both check the value, but only one process can take the value with it. The later-occurring process will read the value as null. This results in a potentially out-of-date or unavailable observation being used to determine what the program will do next. For example, if a map application runs two processes simultaneously that require the same location data, one will take the value first so the other can’t use it. The later process reads the data as null.

How to check race condition ?

A race condition is usually difficult to reproduce, debug, and eliminate. We describe the bugs introduced by race conditions as heisenbugs.

Since race conditions are tied to application semantics, there’s no general way to detect them. Multi-threaded unit tests with a focus on test result stability will help but are unlikely to provide a 100% guarantee.

Fortunately, there are several techniques to avoid or eliminate race conditions. Knowing these techniques, we may want to ensure their usage in code reviews.

How to prevent race condition ?

There’re two kinds of approaches to fight race conditions:

  • Avoid shared states. This means reviewing code to ensure when shared resources are part of a system or process, atomic operations are in place that run independently of other processes and locking is used to enforce the atomic operation of critical sections of code. Immutable objects can also be used that cannot be altered once created.
  • Use thread synchronization. Here, a given part of the program can only execute one thread at a time.

What is data race?

The race condition in the aforementioned example is caused by accessing — including writing — the same memory location by parallel instructions without any atomicity contract.

We refer to this occurrence as a data race. A data race occurs when two threads access the same variable concurrently, and at least one of the accesses is a write. The data race concept is more specific to memory access in a particular concurrency model and, thus, varies across platforms.

Those can be resolved by ensuring atomicity on increment/decrement operations (for example, by using locks), same as with the counter increment example. By protecting every operation, we would get rid of the data race, but the race condition would still be present unless we put the entire implementation into a critical section.

Unlike race conditions, a data race on a particular platform has a strict definition that is not dependent on program semantics. This provides the ability to detect data races automatically.

--

--