I read about usage of C volatile keyword in memory-mapped hardware register, ISR, and multithreaded program.
1) register
uint8_t volat
As for case 2),
I have written the same code as case 2) in your question many times, and did NOT meet any problems. I think this is because the modern compiler can handle this situation. Say, the compiler can "see" I change "flag" inside "rx_isr", and do not add any optimization. However, this is insecure due to the following reasons:
1) optimization level of your compiler, which may affect the following reason 3)
2) calling method of your isr, may be a function pointer is out of compiler's view
3) compiler implementation, different compiler may have different definition of "see flag changed in isr"
...
So, to be secure and portable to the maximum extent, just add "volatile".