If interrupt on change is reliable, you just use the interrupt to set a flag (or two). You can poll and reset the flag in the main code.
This has the advantage of being non-blocking and you aren't hung up in a while(1) {} loop.
Most arithmetic operations including something as simple as "Flag = 0" are not atomic and the value can change in the interrupt while the main code is still working with the variable. So, in your main code, disable the interrupts momentarily when you reset the flag. Depending on the code actually emitted by the compiler, you might get away without doing this for a simple flag. You will not get away with it if you use any kind of counter. At some point, the interrupt handler will change the value while you are changing a previous value.
Take "Flag = Flag - 1". You can see that the first thing is to load the existing value (one instruction, maybe two), decrement the value (another instruction) and save the value (one instruction, maybe two). During the sequence, an interrupt can come along and increment the value after the value is fetched and before it is replaced and if this happens, you will miss a count.