However, this is not the case for atomic operations (which are generally specifically intended for communication via shared variables). This optimization of removing the writing thread entirely isn't allowed if atomic operations are used, because those actually do come with a guarantee that other threads will get to see the update in finite time.
Go was incorrectly "optimizing" the atomic operations out entirely. It's a fairly subtle bug, actually, but still likely a big deal for the few programs communicating via shared variables.
That sounds more like volatile than atomic. At its core, atomic just means that observer may see either pre-update or post-update state but won't see intermediate states.
According to the comments on the bug report, this behavior is inspired by C++'s <atomic> library, which guarantees cross-thread visibility.
Only in the sense that they won't see inconsistent (intermediate) states.
Atomicity shouldn't guarantee order per se - if you want both, you need a mutex.
It is possible to have a model where all atomic operations are relaxed (i.e. unordered) and use explicit barriers for ordering (which is closer to how some, but not all, CPUs work), but it is significantly harder to reason about and prove algorithms correct under it.
edit: wording
Still the C++ spec has wording about making stores visible in a reasonable time. The wording is non-normative as they run out of time (ah!) while trying to come up with a more formal (and implementable) specification.
edit: oh, I see I wrote 'default visibility' instead of 'default ordering'.
"....Escape Analysis and Intrinsics, two commonly used HotSpot optimization techniques. I'll show how a combination of these two features can optimize away IndexOutOfBoundsExceptions in some corner cases where they are required by the standard..."
In doing so, they must have botched something, because now some atomic operations (IE. operations that shouldn't be interruptible by another thread) are completely optimized away.
This is quite a big issue because any multi-threaded program will use these (they are the only way to do lock-free code).
This bug is related to the compiler deciding to optimize the loop. All modifications of variables in the loop are being batched till the loop exits, but it never exits therefore none of the modifications ever happen. In most cases this would be fine as the side-effects of modifying the variables in the loop wouldn't need to visible anywhere else until the loop exited.
If you remove the loop and just modify the atomic variable once, the modification is eventually happens and is seen by the second go routine.