* Jeff Learman <
jeff.l...@gmail.com> [220610 13:23]:
> Unlike C, Go has no `volatile` keyword. Therefore, the compiler is allowed
> to cache a value that is never updated in the scope that it sees, and
> there's no way for us to tell it not to do that.
Actually, sync/atomic does essentially the same thing that volatile does
in C. Volatile ensures that the variable is not register-optimized,
that reads and writes to it are not optimized away when local code can
be proven to not observe those actions, and that reads and writes of
properly aligned values whose size is the machine word size happen
atomically (it also ensures proper alignment). sync/atomic does just
that.
For Microsoft C/C++, for architectures other than arm, volatile, by
default, also prevents reordering of reads and writes to non-volatile
variables around a read or write to a volatile variable. The ISO
definition of volatile explicitly does not require this, favoring the
std::atomic<T> as the mechanism to effect this.
There was discussion a number of years back (8 or more?) about whether
the Go Memory Model explicitly specified, implicitly specified, or did
not specify that sync/atomic provided a guarantee about not reordering
non-atomic reads and writes around atomic operations. The current
version of the memory models says under "Advice" near the beginning of
the document:
To serialize access, protect the data with channel operations or
other synchronization primitives such as those in the sync and
sync/atomic packages.
This sounds to me like an explicit declaration.
> Issues like this aren't
> really data races, but they are caught by the race detector.
Yes, they are. While amd64 and arm64 architectures will ensure, at the
CPU level, that a single instruction read or write to properly aligned
memory will always read or write the whole value atomically, not all
architectures do (especially many RISC architectures). Also, without
explicit memory barrier instructions, the amd64 (and I think arm64)
instructions will not guarantee observability to other cores.
You really should read the link Nigel gave below.
The OP said "I do not want to use atomic operations or locking to remove
this race condition for performance reasons." I believe the OP should
try sync/atomic. It should not give any statistically significant
performance difference from using the volatile keyword in C, as I would
expect C to use a memory barrier for volatile accesses so that other
cores and other hardware on the bus can observe them.
...Marvin