The first problem (non-atomic operations) is to restrict any variables shared between an ISR, signal handler and the “regular” part of a program to the sig_atomic_t type. This requires the cooperation of a compiler to ensure all operations performed to a variable of this type is atomic.
This sig_atomic_t type is an integer. The width, however, depends on the platform and architecture.
The second program (the compiler being too smart and optimize code that should not be optimized) is fixed by the word volatile. Any variable tagged with volatile in its declaration tells the compiler that “it may be changed asynchronously”. As a result, if a condition involves a volatile variable, the compiler will not try to be smart and optimize the control statement out.
A good article to read is this article from CERT.