Date: Fri, 9 Oct 2026 14:27:55 +0800
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
>>
>
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-09 06:28:15
