12
votes

The C standard states that the volatile keyword should be used in the definition of a variable when there's a chance that the variable's value could change outside the normal flow of execution of the program.

If a global variable is changed (written) during normal execution flow and only read outside this normal flow (in an interrupt). Does this variable need to be volatile ? And why ?

1
Short answer: yes. What makes you think it should not need to be declared volatile? - Jabberwocky
@Jabberwocky because the variable didn't "change" outside the normal flow. It is modified only in normal flow - Julien
If the interrupt can interrupt execution at any time, then the variable needs to be either protected by some synchronization mechanism; or be volatile and atomic. In Standard C the interrupt handler should only set a volatile sig_atomic_t flag; specific platforms might provide further allowed behaviour for interrupts - M.M
@Julien if it's not volatile then it's undefined behaviour due to a data race; also the compiler might perform optimizations around the writing of the variable that would impact the values read - M.M

1 Answers

7
votes

If a global variable is changed (written) during normal execution flow and only read outside this normal flow (in an interrupt). Does this variable need to be volatile?

Yes absolutely.

And why?

To ensure proper execution of the interrupt handler (rather than the normal flow).


Let me elaborate.

Imagine you have a variable like this:

int x;

You are modifying this variable in the normal flow of the program as this:

void modify(int *x){...some code here...}

And in the interrupt service routine, you are reading the variable.

Remember that an interrupt can occur asynchronously(at any time). Also remember that the compiler will first convert your code into a series of machine instructions which could look something like this:

load val from mem to register
perform modification operations
store value from registers to memory
perform other operations where the variable is used

Now, the compiler may optimise this program to reduce the number of memory read-writes as such:

load value
perform modifications
use value
...
modify register content
...
use
...
keep using value from the registers without ever storing in the memory.

In such a case, if an interrupt occurs, (note that the interrupt context is usually different from the normal context and thus has different set of registers in a lot of architectures (say arm...)), it will attempt to read the value of the variable from the memory. But the contents of the memory have never been changed because of compiler optimisation.

So, the ISR could read an old value (worse still-we can't definitely say how old a value) which would result in unintended behaviour.

So, the variable should be declared as volatile to prevent the compiler from meddling with the program.