So, what behavior of the program do you think? If you think the program should be undefined behavior because the program contains a data race, let's step-by-step to go through the rules in [intro.race] p17. It's true that `#1` and `#2` are two
potentially concurrent conflicting actions, and neither happens before the other. The crux is whether they satisfy the condition:
at least one of which is not atomic. If one of them is non-atomic, then the condition is satisfied; therefore, the program contains a data race. If they are both atomic operations, the condition is false; no data race is contained. As I commented above, since the standard lets implementations define the semantics of the access, and a hypothetical implementation can define `#1` as `std::atomic_ref<int>(value).load()` and `#2` as `std::atomic_ref<int>(value).store(1)`; i.e., they're atomic operations, I don't think the crux condition in
[intro.race] p17 is true. So, the program under this specified semantics shouldn't be UB. How do you explain this point?
On 09/10/2026 09:16, jim x via Std-Discussion wrote:
> If the implementation defines that accesses to volatile variables
> are atomic, then they are atomic.
>
>
> In this case, does the program contain a data race as per [intro.race]
> p17? If not, since the behavior depends on how the implementation define
> the semantics, does that mean the behavior of the program should be
> implementation-defined?
>
"Implementation-defined" in the standards does not just mean that the
implementation has to treat the construct in some particular way. It
means that the standard gives a range of options of how the
implementation should handle the construct, and that the implementation
must document how it handles them.
If an implementation's manual says that volatile accesses are atomic
(not unreasonable on single-core non-superscaler targets like most
microcontrollers), then the programmer can rely on the volatile accesses
being atomic. But that does not mean unsynchronised volatile accesses
to the same address in different threads is implementation-defined
behaviour, or should be called such in the C++ standards.