C#のvolatileは次のような特性があって(少々省略してるけど)、完全なメモリバリアではない。

 読み取りと書き込みは、volatile の読み取り前に移動することができない。
 読み取りと書き込みは、volatile の書き込み後に移動することができない。

なので、
CPU内での命令の並び替え(OoO)でs_y, s_xの読み取り操作が
書き込み操作の前に移動することがありえる。

s_x = 1; // W
s_ya = s_y; // W, R

これが、こうなる。

var temp = s_y; // R操作がW操作より先行することはルール違反ではない
s_x = 1; // W
s_ya = temp; // W

対策としては明示的にメモリバリアを使いましょうとなる。

s_x = 1; // W
Thread.MemoryBarrier(); // これで完全な分離が可能
s_ya = s_y; // W, R