The answers given above are excellent enough to explain technically what is race condition.
I just want to add explanation from a layman's term/perspective:
'Race condition' is like in a race which involves more than 1 participant. Whoever reach the finishing line first is the only winner. We assume chances of winning are equal among participants. Let say the race is repeated more than once. So we can't predict exactly who will be the winner in each race. There is always a potential that different winner will win in each race.
Here where the problem comes in - If the finishing line is a resource, and a participant is a process, potentially different process will reach the resource at the end of every race and become a winner.
The problem involving race condition is that if process A changed the value in the beginning of 'race', it is not guaranteed that process A will reach the same value in the resource again in the end (finishing line), since A potentially might lose the race. If other process e.g. B become the winner, then B may change the value set by A before process A reach it. If this happened, process A lose its value and will cause problem to process A.
So issue with 'race condition' is the potential of a process lost its value from shared resource, caused by the modification by other process. Race condition is not a problem/issue, if
- no change/update happened, or
- if the same process able to regain and control its value, or
- no sharing resource involved.
Problem with race condition can be solved by adding an 'assurance' that no other process can access the shared resource while a process is using it (read or write). The period of time for the assurance is called the 'critical section'.
This assurance can be provided by creating a lock. E.g. If a process need to use a shared resource, it can lock the resource and release it when it is done, as the steps shown below. The lock may use the mechanism called Semaphore or Mutex. Meanwhile other process that need to use the shared resource will do the same steps.
wait until Mutex is unlockedset Mutex=lockbegin read/write value in shared resource..... do somethingfinish read/write value in shared resourceset Mutex=unlock
This way a process A can ensure no other process will update the shared resource while A is using the resource. The same issue will apply for thread.