The underling effect of volatile is that the compiler turns off certain optimisations to do with instruction reordering and aggressive caching in registers without stores.
However in most places that a typical non-firmware, non-driver programmer would use volatile they really should be using a memory fence (acquire, release or atomic store).