If the variable might be changed by another thread needs something to force the compiler to spill the value to memory, and retrieve a new value from memory.
For the typical single core processor that FreeRTOS targets, volatile will suffice. It might not be good enough on a multi-core CPU or for DMA as volatile might not force a cache flush to transfer data between other masters.
If full program optimization is known not to be (and never will be) present, then calling a function outside the translation unit will normally be good enough, but whole program optimizations can break this.
Beyond this, C11 defined some memory barriers in stdatomic.h and many compilers offer their own.
The critical section code may well have such a barrier included as part of the hardware API (I think ARM has the presence of one as part of its API)
This is in interesting question, and I expect to see a couple of interesting answers here
Richard Damon beats me, he was quicker Yet I will post my text.
Volatile means that the value of a variable may change any moment, either from an ISR or from another task, that makes no difference.
When a variable has the volatile attribute, the compiler will do a fetch in each occasion where it is mentioned. Without the attribute, the value may be stored temporarily in a register, in order to save a fetch from RAM.
A critical section is needed for read/modify/write operations: