Why do you mark a variable shared between an interrupt service routine and your main loop as volatile, and what does volatile NOT protect you from?
technical-conceptual · Junior level · software-engineering
What the interviewer is really asking
Checks whether the candidate understands what volatile actually guarantees (no compiler caching of reads/writes) versus what it does not (atomicity), and that they know to also protect multi-byte access.
What to say
- Explain that volatile stops the compiler from caching the variable in a register or optimizing away reads, so the main loop always re-reads the value the ISR updated in memory.
- Say volatile does NOT make access atomic: a 32-bit counter on an 8-bit MCU is read and written in multiple instructions, so an interrupt can fire mid-update and corrupt it.
- Describe the fix for non-atomic access: briefly disable interrupts (a critical section) or use the smallest type the core writes atomically while you copy the value out.
What to avoid
- Claiming volatile makes operations thread-safe or atomic.
- Saying you mark everything volatile by default 'to be safe' without naming the read-caching problem it solves.
- Confusing volatile with const, or thinking it disables interrupts.
Example answers
Strong: volatile tells the compiler the value can change behind its back, so it can't keep a stale copy in a register across loop iterations. But it doesn't make access atomic. If my ISR updates a 32-bit tick counter and my main loop reads it, on a smaller core that read takes several instructions, so an interrupt could land mid-read and give me a torn value. I'd disable interrupts briefly while I copy the counter out, then re-enable, to make that read atomic.
Weak: You add volatile so the variable is safe to share between the interrupt and the main code. It basically locks it so they don't conflict, and then you don't have to worry about race conditions.