C++ Logo

std-discussion

Advanced search

Re: Does the C++ abstract machine recognize a temporal order of execution?

From: jim x <xmh970252187_at_[hidden]>
Date: Fri, 12 Jun 2026 17:29:12 +0800
>
> This doesn't enforce sequential execution however, since the abstract
> machine is allowed to time travel and see what the result will be and
> execute the second statement using that value before it executes the first.


This is not what an abstract machine does; instead, it's what a conforming
implementation can do. All semantics and structures defined in the abstract
machine aren't changed or reordered; they're used to infer the observable
behavior.

On Fri, Jun 12, 2026 at 4:45 PM Jennifier Burnett <jenni_at_[hidden]>
wrote:

> > I talked about that, for two evaluations `A` and `B`, whether the
> control flow executes `A` at a point in time that is no later than when it
> executes `B` is a valid semantics in the abstract machine?
>
> To summarise the rest of the thread: VLIW hardware and OoO hardware will
> allow executing instructions that correspond to two different statements at
> the same time. The standard only requires that if one statement
> happens-before another statement, the results of the first statement must
> be visible to the second. This doesn't enforce sequential execution
> however, since the abstract machine is allowed to time travel and see what
> the result will be and execute the second statement using that value before
> it executes the first.
>
> The ultimate point is: if an execution produces the same results as
> sequential execution, it's allowed even if the execution is not itself
> sequential.
>
> Once multiple threads get involved things get a bit wibbly, but that's due
> to inter-thread visibility issues rather than anything to do with
> single-threaded semantics.
>
>
> On 12 June 2026 07:17:16 BST, jim x via Std-Discussion <
> std-discussion_at_[hidden]> wrote:
>
>> But there’s nothing else to debate here. We already explained what
>>> behavior you can expect with this.
>>
>>
>> However, the question in my OP is not about observable behavior. I talked
>> about that, for two evaluations `A` and `B`, whether the control flow
>> executes `A` at a point in time that is no later than when it executes `B`
>> is a valid semantics in the abstract machine? Of course, a real
>> implementation doesn't need to emulate the semantics of the abstract
>> machine.
>>
>> On Fri, Jun 12, 2026 at 2:09 PM Tiago Freire <tmiguelf_at_[hidden]>
>> wrote:
>>
>>>
>>>
>>> > The OP is talking about the semantics and structure in the abstract
>>> machine, not only the observable behavior. A possible observable behavior
>>> is justified as valid since we infer that from the semantics and structure
>>> in the abstract machine. So, talking about whether this is a valid
>>> semantics in the abstract machine is necessary.
>>>
>>>
>>>
>>> You already got your answer! That is the answer to what the “abstract
>>> machine” is expected to do. What else do you want?
>>>
>>>
>>>
>>> The concept of the “abstract machine” is only about how the code should
>>> be interpreted, it is not an emulator that you should create, and it does
>>> not define everything.
>>>
>>>
>>>
>>> The “abstract machine” allows for unspecified behavior; but code must
>>> run on real machines and on real machines something must always happen.
>>>
>>> On some devices the result of the load will always going to be 1, on
>>> others it sometimes is going to be 0.
>>>
>>> And the “abstract machine” is not going to tell you which one is right,
>>> it just shrugs its shoulders and says “yes”. Because different systems do
>>> different things, and this is allowed. And this is especially the case for
>>> multi-threaded systems.
>>>
>>>
>>>
>>> You can call it an “incomplete non-deterministic abstract machine” if
>>> you want to be more exact.
>>>
>>>
>>>
>>> But there’s nothing else to debate here. We already explained what
>>> behavior you can expect with this.
>>>
>>> All of your questions have been answered.
>>>
>>>
>>>
>>> If you still think that there is still an open question, there’s nothing
>>> I can do to help you. My capacity for explaining things is limited and I
>>> can’t make it understand it on your behalf.
>>>
>>>
>>>
>>>
>>>
>>> *From:* jim x <xmh970252187_at_[hidden]>
>>> *Sent:* Friday, June 12, 2026 04:45
>>> *To:* Tiago Freire <tmiguelf_at_[hidden]>
>>> *Cc:* std-discussion_at_[hidden]
>>> *Subject:* Re: [std-discussion] Does the C++ abstract machine recognize
>>> a temporal order of execution?
>>>
>>>
>>>
>>> In your OP example if you find that 'now1 < now2', the result of the
>>> atomic load being 0 is a valid outcome.
>>>
>>>
>>>
>>> Yeah, I keep agreeing that this is a valid possible execution in the
>>> abstract machine.
>>>
>>>
>>>
>>> I believe you got lost in nuances of distinctions without a difference.
>>>
>>>
>>>
>>> The OP is talking about the semantics and structure in the abstract
>>> machine, not only the observable behavior. A possible observable behavior
>>> is justified as valid since we infer that from the semantics and structure
>>> in the abstract machine.
>>>
>>>
>>>
>>> So, talking about whether this is a valid semantics in the abstract
>>> machine is necessary.
>>>
>>>
>>>
>>> On Thu, Jun 11, 2026 at 6:33 PM Tiago Freire <tmiguelf_at_[hidden]>
>>> wrote:
>>>
>>> I keep repeating and I don't think you understand what we are saying.
>>>
>>>
>>>
>>> In your OP example if you find that 'now1 < now2', the result of the
>>> atomic load being 0 is a valid outcome.
>>>
>>>
>>>
>>> I believe you got lost in nuances of distinctions without a difference.
>>>
>>>
>>>
>>> Discussing anything else is pointless regardless of whatever it is you
>>> hope to practically achieve with this question.
>>>
>>>
>>> ------------------------------
>>>
>>> *From:* Std-Discussion <std-discussion-bounces_at_[hidden]> on
>>> behalf of jim x via Std-Discussion <std-discussion_at_[hidden]>
>>> *Sent:* Thursday, June 11, 2026 11:16:57 AM
>>> *To:* Jennifier Burnett <jenni_at_[hidden]>
>>> *Cc:* jim x <xmh970252187_at_[hidden]>; std-discussion_at_[hidden] <
>>> std-discussion_at_[hidden]>
>>> *Subject:* Re: [std-discussion] Does the C++ abstract machine recognize
>>> a temporal order of execution?
>>>
>>>
>>>
>>>
>>>
>>> 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-12 09:29:30