C++ atomics are no good here, because they are not guaranteed to be lock free or address free.
In POSIX' case, it's up to POSIX operating systems to define reasonable semantics on the memory, using constructs like PTHREAD_PROCESS_SHARED and "robust" pthread mutexes.
That's not right; you can still use std::memory_order to get the memory barriers generated that are required. These are going to obviously be lock free, they deal with memory ordering—what you tried to deal with volatile, but in general case.
See: https://en.cppreference.com/w/cpp/atomic/atomic/store
Effectively std::atomic stores and loads generate volatile accesses plus the required memory barriers to get the desired behavior.
And yes, that's not stupid. It's actually faster than all the register "optimizations" for practical use cases in fast VM's. Register saving across calls and at the GC is much more expensive. mem2reg is an antipattern mostly