exactly. The fence is required even when communicating with a signal handler (or interrupt handler) on the same thread. For for the multithreaded case, depending on the architecture, the compiler barrier is likely not sufficient and an actual hardware #StoreStore fence might be required.
A specular barrier is needed on the reader side.
>data[write_position] = value;
>COMPILER_BARRIER(); // __asm__ volatile("":::"memory");
>write_position = (write_position + 1U) % LENGTH;
and same in Skip()