Date: Sat, 10 Oct 2026 09:49:07 +0800
>
> “volatile” is not atomic, I don’t know where you got that idea.
The idea is sourced from, since the standard states that the semantics of
access through volatile glvalue are implementation-defined, an
implementation can define the operation at `#1` as equivalent to `
std::atomic_ref<int>(value).load()`, and the operation at `#2` as
equivalent to `std::atomic_ref<int>(value).store()`, both are atomic
operations defined in <atomic>, so under the specified semantics, why don't
we consider them atomic?
On Fri, Oct 9, 2026 at 9:19 PM Tiago Freire <tmiguelf_at_[hidden]> wrote:
> 1. “volatile” is not atomic, I don’t know where you got that idea.
>
> 2. Even with atomics there would be a data race, at least in the sense
> that running it multiple times will yield different results. Atomics only
> guarantee visibility of different types of side-effects (depending on the
> type of atomic operation) they do not the synchronize the execution across
> different threads. This is not exactly UB, what it does is actually very
> well defined, but the outcome of the operation is dependent on a factor
> that you neither control or the language specifies.
>
>
>
>
>
> *From:* Std-Discussion <std-discussion-bounces_at_[hidden]> *On
> Behalf Of *jim x via Std-Discussion
> *Sent:* Friday, October 9, 2026 08:28
> *To:* Jennifier Burnett <jenni_at_[hidden]>
> *Cc:* jim x <xmh970252187_at_[hidden]>; jim x via Std-Discussion <
> std-discussion_at_[hidden]>
> *Subject:* Re: [std-discussion] Is this program undefined-behavior or
> implementation-defined behavior?
>
>
>
> The issue is not whether an implementation can guarantee a specific
> behavior for an operation that has UB. The issue is why the operations at
> `#1` and `#2` are still considered non-atomic under the concrete
> semantics: An access to a volatile int glvalue value is defined to have
> the exact semantics of std::atomic_ref<int>(value).load() for reads, and
> std::atomic_ref<int>(value).store() for writes.
>
>
>
> The premise you think the program is UB is that you think such two
> operations are non-atomic and therefore cause the program to contain a data
> race as per [intro.race] p17. My question is why such two operations are
> non-atomic under [intro.race] p17 when their semantics are specified as: An
> access to a volatile int glvalue value is defined to have the exact
> semantics of std::atomic_ref<int>(value).load() for reads, and
> std::atomic_ref<int>(value).store() for writes.
>
>
>
> On Fri, Oct 9, 2026 at 2:16 PM Jennifier Burnett <jenni_at_[hidden]>
> wrote:
>
> I'm not sure there's a conflict? Implementations are perfectly allowed to
> define undefined behaviour to have some specific behaviour. I'm allowed to
> create an implementation that has a defined behaviour for *all* data races,
> for example. The standard says that anything can happen when undefined
> behaviour occurs, and implementation-defined behaviour does fall under the
> category of "anything".
>
>
>
> On 9 October 2026 06:11:15 BST, jim x via Std-Discussion <
> std-discussion_at_[hidden]> wrote:
>
> Consider this example:
>
> ````cpp
>
> #include
>
>
>
> int main(){
>
> volatile int value = 0;
>
> std::jthread t1([&](){
>
> auto i = value; // #1
>
> });
>
> std::jthread t2([&](){
>
> value = 1; // #2
>
> });
>
> }
>
> ````
>
> People think this program should contain a data race because `#1` and `#2`
> are *non-atomic* operations, which satisfies the condition in [intro.races]
> p17
> <https://eel.is/c++draft/intro.races#17>
>
> Two actions are *potentially concurrent*
> <https://eel.is/c++draft/intro.races#def:potentially_concurrent> if
>
> they are performed by different threads, or
> <https://eel.is/c++draft/intro.races#17>
>
> The execution of a program contains a data race if it contains two
> potentially concurrent conflicting actions, *at least one of which is not
> atomic*, and neither happens before the other, except for the special
> case for signal handlers described below. Any such data race results in
> undefined behavior ([ub:intro.races.data]).
>
>
>
> However, this opinion is based on the premise that they consider the
> operations at `#1` and `#2` to be non-atomic operations in any way.
> However, [dcl.type.cv] p5 <https://eel.is/c++draft/dcl.type.cv#5>
> simultaneously states:
>
> *The semantics of an access through a volatile glvalue are
> implementation-defined.*
>
>
>
> How about if a hypothetical implementation specifies the semantics as
> follows:
>
> An access to a volatile int glvalue value is defined to have the exact
> semantics of std::atomic_ref<int>(value).load() for reads, and
> std::atomic_ref<int>(value).store() for writes.
>
>
>
> Under these specified semantics, `#1` and `#2` should be considered as
> atomic operations, which won't satisfy the condition in [intro.race] p17,
> therefore no data race. From this perspective, isn't the program
> implementation-defined behavior? That is, whether the program contains a
> data race depends on how the implementation specifies the semantics
>
>
> “volatile” is not atomic, I don’t know where you got that idea.
The idea is sourced from, since the standard states that the semantics of
access through volatile glvalue are implementation-defined, an
implementation can define the operation at `#1` as equivalent to `
std::atomic_ref<int>(value).load()`, and the operation at `#2` as
equivalent to `std::atomic_ref<int>(value).store()`, both are atomic
operations defined in <atomic>, so under the specified semantics, why don't
we consider them atomic?
On Fri, Oct 9, 2026 at 9:19 PM Tiago Freire <tmiguelf_at_[hidden]> wrote:
> 1. “volatile” is not atomic, I don’t know where you got that idea.
>
> 2. Even with atomics there would be a data race, at least in the sense
> that running it multiple times will yield different results. Atomics only
> guarantee visibility of different types of side-effects (depending on the
> type of atomic operation) they do not the synchronize the execution across
> different threads. This is not exactly UB, what it does is actually very
> well defined, but the outcome of the operation is dependent on a factor
> that you neither control or the language specifies.
>
>
>
>
>
> *From:* Std-Discussion <std-discussion-bounces_at_[hidden]> *On
> Behalf Of *jim x via Std-Discussion
> *Sent:* Friday, October 9, 2026 08:28
> *To:* Jennifier Burnett <jenni_at_[hidden]>
> *Cc:* jim x <xmh970252187_at_[hidden]>; jim x via Std-Discussion <
> std-discussion_at_[hidden]>
> *Subject:* Re: [std-discussion] Is this program undefined-behavior or
> implementation-defined behavior?
>
>
>
> The issue is not whether an implementation can guarantee a specific
> behavior for an operation that has UB. The issue is why the operations at
> `#1` and `#2` are still considered non-atomic under the concrete
> semantics: An access to a volatile int glvalue value is defined to have
> the exact semantics of std::atomic_ref<int>(value).load() for reads, and
> std::atomic_ref<int>(value).store() for writes.
>
>
>
> The premise you think the program is UB is that you think such two
> operations are non-atomic and therefore cause the program to contain a data
> race as per [intro.race] p17. My question is why such two operations are
> non-atomic under [intro.race] p17 when their semantics are specified as: An
> access to a volatile int glvalue value is defined to have the exact
> semantics of std::atomic_ref<int>(value).load() for reads, and
> std::atomic_ref<int>(value).store() for writes.
>
>
>
> On Fri, Oct 9, 2026 at 2:16 PM Jennifier Burnett <jenni_at_[hidden]>
> wrote:
>
> I'm not sure there's a conflict? Implementations are perfectly allowed to
> define undefined behaviour to have some specific behaviour. I'm allowed to
> create an implementation that has a defined behaviour for *all* data races,
> for example. The standard says that anything can happen when undefined
> behaviour occurs, and implementation-defined behaviour does fall under the
> category of "anything".
>
>
>
> On 9 October 2026 06:11:15 BST, jim x via Std-Discussion <
> std-discussion_at_[hidden]> wrote:
>
> Consider this example:
>
> ````cpp
>
> #include
>
>
>
> int main(){
>
> volatile int value = 0;
>
> std::jthread t1([&](){
>
> auto i = value; // #1
>
> });
>
> std::jthread t2([&](){
>
> value = 1; // #2
>
> });
>
> }
>
> ````
>
> People think this program should contain a data race because `#1` and `#2`
> are *non-atomic* operations, which satisfies the condition in [intro.races]
> p17
> <https://eel.is/c++draft/intro.races#17>
>
> Two actions are *potentially concurrent*
> <https://eel.is/c++draft/intro.races#def:potentially_concurrent> if
>
> they are performed by different threads, or
> <https://eel.is/c++draft/intro.races#17>
>
> The execution of a program contains a data race if it contains two
> potentially concurrent conflicting actions, *at least one of which is not
> atomic*, and neither happens before the other, except for the special
> case for signal handlers described below. Any such data race results in
> undefined behavior ([ub:intro.races.data]).
>
>
>
> However, this opinion is based on the premise that they consider the
> operations at `#1` and `#2` to be non-atomic operations in any way.
> However, [dcl.type.cv] p5 <https://eel.is/c++draft/dcl.type.cv#5>
> simultaneously states:
>
> *The semantics of an access through a volatile glvalue are
> implementation-defined.*
>
>
>
> How about if a hypothetical implementation specifies the semantics as
> follows:
>
> An access to a volatile int glvalue value is defined to have the exact
> semantics of std::atomic_ref<int>(value).load() for reads, and
> std::atomic_ref<int>(value).store() for writes.
>
>
>
> Under these specified semantics, `#1` and `#2` should be considered as
> atomic operations, which won't satisfy the condition in [intro.race] p17,
> therefore no data race. From this perspective, isn't the program
> implementation-defined behavior? That is, whether the program contains a
> data race depends on how the implementation specifies the semantics
>
>
Received on 2026-10-10 01:49:27
