Date: Fri, 09 Oct 2026 08:09:26 +0100
If the implementation defines that accesses to volatile variables are atomic, then they are atomic. If the implementation gives them the exact semantics of an atomic accesses but neglects to formally define them as atomic, that's an oversight on the implementation's part. The defined behaviour of a particular implementation always overrides definitions in the standard, so long as the defined behaviour is a superset of the standard-specified behaviour.
On 9 October 2026 07:27:55 BST, jim x <xmh970252187_at_[hidden]> wrote:
>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
>>>
>>
On 9 October 2026 07:27:55 BST, jim x <xmh970252187_at_[hidden]> wrote:
>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-09 07:09:40
