c volatile keyword and memory cache
The 'volatile' keyword is used to tells the compiler to fetch a variable each time from memory rather then use a "compiler-generated" cached version in registers or optimise certain code (like entirely optimized out memory access code).
1. why need volatile?
suppose 2 processes P1 & P2 like below,
// Process 1
char *p = 'a'; //shared between P1 and P2
while (*p) {}
// Process 2
char *p = 'a'; //shared between P1 and P2
char i = 'a';
while (1) {
*p = i++;
}
the optimized code for P1 may looks like below, so P1 while loop run without checking *p. To prevent this optimization, use 'volatile' keyword for *p.
// Process 1
char *p = 'a'; //shared between P1 and P2
if (*p)
while (1) {} // always run without check *p.
2. why memory cache comes to play?
Although volatile requires access memory for data, but there is a cache between CPU and memory, and CPU will always fetch data from cache if there is a match. So if P1 & P2 all have matched cache for *p, will P1 read P2's new data?
In uniprocessor system, there is only 1 cache, so P1 can read P2's new data.
How about multiprocessor system? Each cpu has its own cache, and may also has L2-cache. P2 update new data in its cache A. P1 read data from its own cache B. Thanks to cache snooping/coherency, cache are synced from all CPU. So P1 can still read P2's new data.
The problem comes when *p is updated by other hardware rather than CPU. 1) *p may refer to a hardware status register, 2) *p may refer to a region where other hardware copy data using DMA. So *p memory location is updated without CPU/cache system knowing, and cache snooping/coherency not work for this sutiation. So if P1 read *p now and has cache match, then P1 will read old data. How to read latest data by P1? 1) force a cache refresh by invalidate cache, or 2) let *p reside in uncached memory location.
refer:
https://*.com/questions/7872175/c-volatile-variables-and-cache-memory?rq=1
https://*.com/questions/18695120/volatile-and-cache-behaviour