Date: Thu, 11 Jun 2026 11:58:42 +0100
> The structure and semantics inside the abstract machine are not necessarily preserved in the observable behavior, but they are an important part of reasoning about possible execution outcomes
Exactly, they are for reasoning about *possible execution outcomes*. In the example you just provided the store and the observation of the time point provide an execution outcome: the store will become visible and the time point will be read. Exactly what the time point might be is variable but the point I'm making is that it doesn't matter what order they happen in: the end result is the same. If the store happens after the observation of the time point or vice versa is impossible to observe (and trying to figure out exactly what a store "happening" means without invoking happens-before and inter-thread visibility is a whole separate issue).
Asking about if a machine that doesn't exist does or does not do something that is impossible to tell if it's doing based on outcomes is a futile exercise.
On 11 June 2026 10:16:32 BST, jim x <xmh970252187_at_[hidden]> wrote:
>> so the question of whether one statement executes before another on a
>> machine that doesn't exist and will never execute the code is vacuous. You
>> need to provide a visible outcome that you are expecting to be possible or
>> not possible on the hypothetical machine.
>>
>
>The structure and semantics inside the abstract machine are not necessarily
>preserved in the observable behavior, but they are an important part of
>reasoning about possible execution outcomes. For instance, the modification
>order of an atomic object is only the semantic inside the abstract machine,
>and it is not the observable behavior; It is because of its existence that
>we know what the legitimate possible executions in the abstract machine are
>for a multi-threaded program.
>
>On Thu, Jun 11, 2026 at 4:03 PM Jennifier Burnett <jenni_at_[hidden]>
>wrote:
>
>> I think in this case we're somewhat losing the forest for the trees. How
>> exactly would you test if #1 occurred before #2? The abstract machine is,
>> well, abstract. It doesn't exist and is meaningful only in the possible
>> executions it can allow, so the question of whether one statement executes
>> before another on a machine that doesn't exist and will never execute the
>> code is vacuous. You need to provide a visible outcome that you are
>> expecting to be possible or not possible on the hypothetical machine.
>>
>>
>> On 11 June 2026 08:46:43 BST, jim x <xmh970252187_at_[hidden]> wrote:
>>
>>> In the OP, I don't think `#1` must be visible to `#4` when `now1 < now2`.
>>> As I said above, the visibility is guaranteed by the happens-before that
>>> has a strict definition in the specification. To avoid over-focus on the
>>> inter-thread happens-before, I think the original question can be
>>> simplified as an example that only comprises a single thread.
>>>
>>> ````cpp
>>>
>>> #include <atomic>
>>> #include <chrono>
>>>
>>> std::atomic<int> val = 0;int main(){
>>> val.store(1,std::memory_order::relaxed); // #1
>>> auto c1 = std::chrono::steady_clock::now(); // #2
>>> }
>>>
>>> ````
>>>
>>> The control flow first executes `#1`, then `#2`, while the control flow
>>> executing `#2` samples a global time point. So, the question is: Is `#1`
>>> executed by the control flow at a point in time that is no later than the
>>> time point represented by `c1`? Note that we only talk about this question
>>> in the abstract machine.
>>>
>>> On Thu, Jun 11, 2026 at 3:22 PM Jennifier Burnett <jenni_at_[hidden]>
>>> wrote:
>>>
>>>> Happens-before is very relevant because the question is about visibility
>>>> between threads. The sequencing of statements in c++ is defined by the
>>>> sequenced-before relation, which is implicitly upgraded to a happens-before
>>>> relationship. The OP is asking if a write on one thread must become visible
>>>> to a read on another thread if the latter observes a later time point from
>>>> a call that is sequenced-before the read than the prior does from a call
>>>> that is sequenced-after the write. Without a happens-before relationship
>>>> between the read and the write that simply isn't possible because of
>>>> trivial hardware optimisations like store buffering. Just because an
>>>> execution on one thread happens temporally after an execution on another
>>>> thread does not necessarily mean that the later execution has the same view
>>>> of memory that the earlier one does.
>>>>
>>>> My point is that unless you consider that observing a time point counts
>>>> as a type of write there's no way of establishing the release part of the
>>>> acquire-release relationship that's required for creating the
>>>> happens-before.
>>>>
>>>>
>>>> On 11 June 2026 06:51:46 BST, jim x <xmh970252187_at_[hidden]> wrote:
>>>>
>>>>>
>>>>> What exactly would you be establishing a happens-before relationship
>>>>>> with in the original example?
>>>>>>
>>>>>
>>>>> This is the misunderstanding of the OP. The OP doesn't talk about the
>>>>> happens-before relationship; instead, the intention can be simplified as
>>>>> talking about whether the control flow executing a previous expression
>>>>> occurs in no later time point than the time point it executes a later
>>>>> expression.
>>>>>
>>>>> On Thu, Jun 11, 2026 at 1:37 PM Jennifier Burnett via Std-Discussion <
>>>>> std-discussion_at_[hidden]> wrote:
>>>>>
>>>>>> An acquire barrier is meaningless in this context. An acquire barrier
>>>>>> needs either a release operation or atomic operation preceded by a release
>>>>>> barrier to have any semantics beyond relaxed. What exactly would you be
>>>>>> establishing a happens-before relationship with in the original example?
>>>>>> Assuming the call to now() is an implicit acquire barrier changes nothing
>>>>>> about the semantics because there's no corresponding release for it to
>>>>>> establish a happens-before relationship with. The first thread doesn't even
>>>>>> have any operations other than the call to now() that the acquire barrier
>>>>>> would apply to
>>>>>>
>>>>>> On 11 June 2026 01:37:42 BST, Thiago Macieira via Std-Discussion <
>>>>>> std-discussion_at_[hidden]> wrote:
>>>>>> >On Wednesday, 10 June 2026 16:24:30 Pacific Daylight Time Simon Cooke
>>>>>> wrote:
>>>>>> >> If you don't want that, you need acquire semantics, which will
>>>>>> prevent the
>>>>>> >> write from down after the timestamp() call in #2
>>>>>> >
>>>>>> >This is the essence of the argument: reading from the monotonic clock
>>>>>> should
>>>>>> >be an acquire barrier. The Standard does not say it is, but I think
>>>>>> it should.
>>>>>> >
>>>>>> --
>>>>>> Std-Discussion mailing list
>>>>>> Std-Discussion_at_[hidden]
>>>>>> https://lists.isocpp.org/mailman/listinfo.cgi/std-discussion
>>>>>>
>>>>>
Exactly, they are for reasoning about *possible execution outcomes*. In the example you just provided the store and the observation of the time point provide an execution outcome: the store will become visible and the time point will be read. Exactly what the time point might be is variable but the point I'm making is that it doesn't matter what order they happen in: the end result is the same. If the store happens after the observation of the time point or vice versa is impossible to observe (and trying to figure out exactly what a store "happening" means without invoking happens-before and inter-thread visibility is a whole separate issue).
Asking about if a machine that doesn't exist does or does not do something that is impossible to tell if it's doing based on outcomes is a futile exercise.
On 11 June 2026 10:16:32 BST, jim x <xmh970252187_at_[hidden]> wrote:
>> so the question of whether one statement executes before another on a
>> machine that doesn't exist and will never execute the code is vacuous. You
>> need to provide a visible outcome that you are expecting to be possible or
>> not possible on the hypothetical machine.
>>
>
>The structure and semantics inside the abstract machine are not necessarily
>preserved in the observable behavior, but they are an important part of
>reasoning about possible execution outcomes. For instance, the modification
>order of an atomic object is only the semantic inside the abstract machine,
>and it is not the observable behavior; It is because of its existence that
>we know what the legitimate possible executions in the abstract machine are
>for a multi-threaded program.
>
>On Thu, Jun 11, 2026 at 4:03 PM Jennifier Burnett <jenni_at_[hidden]>
>wrote:
>
>> I think in this case we're somewhat losing the forest for the trees. How
>> exactly would you test if #1 occurred before #2? The abstract machine is,
>> well, abstract. It doesn't exist and is meaningful only in the possible
>> executions it can allow, so the question of whether one statement executes
>> before another on a machine that doesn't exist and will never execute the
>> code is vacuous. You need to provide a visible outcome that you are
>> expecting to be possible or not possible on the hypothetical machine.
>>
>>
>> On 11 June 2026 08:46:43 BST, jim x <xmh970252187_at_[hidden]> wrote:
>>
>>> In the OP, I don't think `#1` must be visible to `#4` when `now1 < now2`.
>>> As I said above, the visibility is guaranteed by the happens-before that
>>> has a strict definition in the specification. To avoid over-focus on the
>>> inter-thread happens-before, I think the original question can be
>>> simplified as an example that only comprises a single thread.
>>>
>>> ````cpp
>>>
>>> #include <atomic>
>>> #include <chrono>
>>>
>>> std::atomic<int> val = 0;int main(){
>>> val.store(1,std::memory_order::relaxed); // #1
>>> auto c1 = std::chrono::steady_clock::now(); // #2
>>> }
>>>
>>> ````
>>>
>>> The control flow first executes `#1`, then `#2`, while the control flow
>>> executing `#2` samples a global time point. So, the question is: Is `#1`
>>> executed by the control flow at a point in time that is no later than the
>>> time point represented by `c1`? Note that we only talk about this question
>>> in the abstract machine.
>>>
>>> On Thu, Jun 11, 2026 at 3:22 PM Jennifier Burnett <jenni_at_[hidden]>
>>> wrote:
>>>
>>>> Happens-before is very relevant because the question is about visibility
>>>> between threads. The sequencing of statements in c++ is defined by the
>>>> sequenced-before relation, which is implicitly upgraded to a happens-before
>>>> relationship. The OP is asking if a write on one thread must become visible
>>>> to a read on another thread if the latter observes a later time point from
>>>> a call that is sequenced-before the read than the prior does from a call
>>>> that is sequenced-after the write. Without a happens-before relationship
>>>> between the read and the write that simply isn't possible because of
>>>> trivial hardware optimisations like store buffering. Just because an
>>>> execution on one thread happens temporally after an execution on another
>>>> thread does not necessarily mean that the later execution has the same view
>>>> of memory that the earlier one does.
>>>>
>>>> My point is that unless you consider that observing a time point counts
>>>> as a type of write there's no way of establishing the release part of the
>>>> acquire-release relationship that's required for creating the
>>>> happens-before.
>>>>
>>>>
>>>> On 11 June 2026 06:51:46 BST, jim x <xmh970252187_at_[hidden]> wrote:
>>>>
>>>>>
>>>>> What exactly would you be establishing a happens-before relationship
>>>>>> with in the original example?
>>>>>>
>>>>>
>>>>> This is the misunderstanding of the OP. The OP doesn't talk about the
>>>>> happens-before relationship; instead, the intention can be simplified as
>>>>> talking about whether the control flow executing a previous expression
>>>>> occurs in no later time point than the time point it executes a later
>>>>> expression.
>>>>>
>>>>> On Thu, Jun 11, 2026 at 1:37 PM Jennifier Burnett via Std-Discussion <
>>>>> std-discussion_at_[hidden]> wrote:
>>>>>
>>>>>> An acquire barrier is meaningless in this context. An acquire barrier
>>>>>> needs either a release operation or atomic operation preceded by a release
>>>>>> barrier to have any semantics beyond relaxed. What exactly would you be
>>>>>> establishing a happens-before relationship with in the original example?
>>>>>> Assuming the call to now() is an implicit acquire barrier changes nothing
>>>>>> about the semantics because there's no corresponding release for it to
>>>>>> establish a happens-before relationship with. The first thread doesn't even
>>>>>> have any operations other than the call to now() that the acquire barrier
>>>>>> would apply to
>>>>>>
>>>>>> On 11 June 2026 01:37:42 BST, Thiago Macieira via Std-Discussion <
>>>>>> std-discussion_at_[hidden]> wrote:
>>>>>> >On Wednesday, 10 June 2026 16:24:30 Pacific Daylight Time Simon Cooke
>>>>>> wrote:
>>>>>> >> If you don't want that, you need acquire semantics, which will
>>>>>> prevent the
>>>>>> >> write from down after the timestamp() call in #2
>>>>>> >
>>>>>> >This is the essence of the argument: reading from the monotonic clock
>>>>>> should
>>>>>> >be an acquire barrier. The Standard does not say it is, but I think
>>>>>> it should.
>>>>>> >
>>>>>> --
>>>>>> Std-Discussion mailing list
>>>>>> Std-Discussion_at_[hidden]
>>>>>> https://lists.isocpp.org/mailman/listinfo.cgi/std-discussion
>>>>>>
>>>>>
Received on 2026-06-11 10:58:53
