A race condition occurs when concurrent execution produces different results because uncontrollable timing determines how operations interleave. Even deadlock-free code can read mixed or outdated shared state when a multi-step operation releases its locks between steps. section 7.4 section 7.0
Listing 7.12 Holding just one lock at a time
public int Add()
{
int leftCopy,rightCopy;
lock(_leftOperandLock)
{
leftCopy = _leftOperand;
}
lock(_rightOperandLock)
{
rightCopy = _rightOperand;
}
return rightCopy + leftCopy;
}
public int SetOperands(int left, int right)
{
lock(_leftOperandLock)
{
_leftOperand = left;
}
lock(_rightOperandLock)
{
_rightOperand = right;
}
}
Compare the separate locks in Add and SetOperands: each protects one access, but neither protects the complete operation, allowing their steps to interleave. section 7.4
Reduce race conditions by applying synchronization at the operation boundary:
- Protect shared data with locks and hold them for the entire operation, while keeping the locked duration as short as practical. section 7.7
- Acquire multiple locks in a consistent lock hierarchy; avoiding multiple simultaneous locks does not automatically make compound operations safe. section 7.7 section 7.3
- Release locks before calling code outside your control, including event handlers, because callbacks can create additional synchronization cycles. section 7.7 section 7.3



















