written 2.8 years ago by |
Race Condition:
A race condition is an undesirable situation that occurs when a device or system attempts to perform two or more operations at the same time, but because of the nature of the device or system, the operations must be done in the proper sequence to be done correctly.
Race conditions are most commonly associated with computer science and programming. They occur when two computer program processes, or threads, attempt to access the same resource at the same time and cause problems in the system.
Race conditions are considered a common issue for multithreaded applications.
A simple example of a race condition is a light switch. In some homes, there are multiple light switches connected to a common ceiling light. When these types of circuits are used, the switch position becomes irrelevant. If the light is on, moving either switch from its current position turns the light off. Similarly, if the light is off, then moving either switch from its current position turns the light on.
With that in mind, imagine what might happen if two people tried to turn on the light using two different switches at the same time. One instruction might cancel the other or the two actions might trip the circuit breaker.
In computer memory or storage, a race condition may occur if commands to read and write a large amount of data are received at almost the same instant, and the machine attempts to overwrite some or all of the old data while that old data is still being read. The result may be one or more of the following:
- the computer crashes or identifies an illegal operation of the program
- errors reading the old data
- errors writing the new data
A race condition can also occur if instructions are processed in the incorrect order.
Suppose two processes need to perform a bit flip at a specific memory location.
Example simultaneous memory processes with a race condition Figure 2. When Process 2 is unaware that Process 1 is performing a simultaneous bit flip, the bit has an ending value of 1 when its value should be 0. Race conditions occasionally occur in logic gates when inputs come into conflict. Because the gate output state takes a finite, nonzero amount of time to react to any change in input states, sensitive circuits or devices following the gate may be fooled by the state of the output and not operate properly.
There are a few types of race conditions. Two categories that define the impact of the race condition on a system are referred to as critical and noncritical:
- A critical race condition will cause the end state of the device, system, or program to change. For example, if flipping two light switches connected to a common light at the same time blows the circuit, it is considered a critical race condition. In software, a critical race condition is when a situation results in a bug with unpredictable or undefined behavior.
- A non-critical race condition does not directly affect the end state of the system, device, or program. In the light example, if the light is off and flipping both switches simultaneously turns the light on and has the same effect as flipping one switch, then it is a non-critical race condition. In software, a non-critical race condition does not result in a bug.
Critical and noncritical race conditions aren't limited to electronics or programming. They can occur in many types of systems where race conditions happen.
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 act 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.
- Check-then-act. This race condition happens when two processes check a value on which they will take each take 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 do you prevent race conditions?
Two ways programmers can prevent race conditions in operating systems and other software include:
- Avoid shared states. This means reviewing code to ensure when shared resources are part of a system or process, atomic operations are in a place that runs 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.