C++ Logo

std-discussion

Advanced search

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

From: Simon Cooke <sicooke_at_[hidden]>
Date: Wed, 10 Jun 2026 16:24:30 -0700
So I'm a little rusty. Apologies if this is completely wrong.

First, creating the threads in both cases means that operations in t1 and
operations in t2 are *not* ordered with respect to one another. You have
zero guarantees over which thread will start to execute first, in which
order, or if they'll even have to co-operatively pre-empt one another on a
single core, or operate across multiple cores. There's always a chance that
something will happen and cause them to swap order, or run in unexpected
ordering, unless you explicitly ad synchronization points.

You state:

> Since the control flow cannot reach #2 without first executing #1, #1 must
> be executed by the control flow at a point in time no later than the time
> point returned by #2.


Control flow can reach #2 without executing #1, because ordering is
relaxed. The CPU is free to move the store instruction beyond timestamp()
call (which will resolve to a single instruction on most architectures). If
you don't want that, you need *acquire* semantics, which will prevent the
write from down after the timestamp() call in #2. The only time anything
gets synchronized here at all is that ending the thread will flush any
pending loads/stores before it dies - so you can guarantee that after the
thread has ended, both #1 and #2 have completed.

Therefore, when now1 < now2, does it imply that #1 is executed by the
> control flow of t1 at a point in time strictly earlier than when #4 is
> executed by the control flow of t2, from the perspective of the abstract
> machine?


 You can't guarantee that all of t2 won't execute before all of t1. And
even if you could guarantee that they would execute in parallel on two
cores, #4 can occur at any point within t2, as again, it has relaxed
ordering. To get the behavior you want, you need to specify that #4 has
*release* semantics.

It'd be different if, say, the code was this:

    auto t1 = std::thread([&]() {
> int temp = timestamp();
>
            val.store(temp,relaxed);

> });
>

... for t1, as val.store() relies on the value read from int temp(), so the
loads/stores involved can't float around and be exercised in sequence.

Does that help at all?

On Wed, Jun 10, 2026 at 3:14 PM Thiago Macieira via Std-Discussion <
std-discussion_at_[hidden]> wrote:

> On Wednesday, 10 June 2026 10:49:17 Pacific Daylight Time Tiago Freire
> wrote:
> > > Inconsistent monotonic clocks are a bug in the platform implementation
> and
> > > a violation of the Standard that should be fixed by said
> implementation.
> > Is it? Regardless, I don't think this is the point being discussed here.
>
> Yes and I agree not what was being discussed.
>
> An inconsistent monotonic clock could show up as a "clock went backwards"
> if
> the thread got de-scheduled from one computing device and scheduled in
> another. The window of time this could happen is very small, and context-
> switching is usually pretty costly, but never say never.
>
> The amount of silicon area and resources on Intel processors dedicated to
> ensuring that the time stamp counters are kept monotonic and clock-
> independent, and yet quick to access, is massive. I don't know about other
> architectures, but it has to be similar.
>
> However, while the inconsistent clock itself was not the point, the
> *consistency* of reading a clock was.
>
> > I think the point being discussed here is if you have a thread X where
> you
> > write the code to do A then B, and you have a thread Y where you write
> code
> > to do C then D, if you can deduce that C happened after B is it
> guaranteed
> > that D happened after A?
> >
> > And the answer to that question is No.
>
> That depends on the sequence of happens-before relationships. We have a
> very
> large section of the Standard dedicated to explaining this.
>
> What is missing is whether there is any happens-before of any kind
> relating to
> the steady_clock. I think there should be.
>
> > For the particular case of reading a clock, I assume that on most
> > implementations a barrier would be involved somewhere, and as you have
> > seemed to correctly point out in a separate email.
>
> I've pointed out one example. And while I think it is necessary for there
> to
> be a happens-before via release/acquire, I am not so certain all
> implementations do it properly.
>
> > But an implementation where reading a clock would still allow for other
> > instructions around it to be reordered before or after the read, looks to
> > me too also be a valid implementation.
>
> Reordering, yes.
>
> The question is back to the point of the OP: is a happens-before
> relationship
> required? The Standard doesn't say anything.
>
> I think it should. Therefore, reordering is permitted, so long as the
> observed
> external behaviour is that of the happens-before sequence.
>
> --
> Thiago Macieira - thiago (AT) macieira.info - thiago (AT) kde.org
> Principal Engineer - Intel Data Center - Platform & Sys. Eng.
> --
> Std-Discussion mailing list
> Std-Discussion_at_[hidden]
> https://lists.isocpp.org/mailman/listinfo.cgi/std-discussion
>

Received on 2026-06-10 23:25:12