What does “strongly happens before” mean?

做~自己de王妃 提交于 2019-12-05 22:09:00

问题


The phrase "strongly happens before" is used several times in the C++ draft standard.

For example: Termination [basic.start.term]/5

If the completion of the initialization of an object with static storage duration strongly happens before a call to std​::​atexit (see , [support.start.term]), the call to the function passed to std​::​atexit is sequenced before the call to the destructor for the object. If a call to std​::​atexit strongly happens before the completion of the initialization of an object with static storage duration, the call to the destructor for the object is sequenced before the call to the function passed to std​::​atexit. If a call to std​::​atexit strongly happens before another call to std​::​atexit, the call to the function passed to the second std​::​atexit call is sequenced before the call to the function passed to the first std​::​atexit call.

And defined in Data races [intro.races]/12

An evaluation A strongly happens before an evaluation D if, either

(12.1) A is sequenced before D, or

(12.2) A synchronizes with D, and both A and D are sequentially consistent atomic operations ([atomics.order]), or

(12.3) there are evaluations B and C such that A is sequenced before B, B simply happens before C, and C is sequenced before D, or

(12.4) there is an evaluation B such that A strongly happens before B, and B strongly happens before D.

[ Note: Informally, if A strongly happens before B, then A appears to be evaluated before B in all contexts. Strongly happens before excludes consume operations. — end note ]

Why was "strongly happens before" introduced? Intuitively, what's its difference and relation with "happens before"?

What does the "A appears to be evaluated before B in all contexts" in the note mean?

(Note: the motivation for this question are Peter Cordes's comments under this answer.)

Additional draft standard quote (thanks to Peter Cordes)

Order and consistency [atomics.order]/4

There is a single total order S on all memory_­order​::​seq_­cst operations, including fences, that satisfies the following constraints. First, if A and B are memory_­order​::​seq_­cst operations and A strongly happens before B, then A precedes B in S. Second, for every pair of atomic operations A and B on an object M, where A is coherence-ordered before B, the following four conditions are required to be satisfied by S:

(4.1) if A and B are both memory_­order​::​seq_­cst operations, then A precedes B in S; and

(4.2) if A is a memory_­order​::​seq_­cst operation and B happens before a memory_­order​::​seq_­cst fence Y, then A precedes Y in S; and

(4.3) if a memory_­order​::​seq_­cst fence X happens before A and B is a memory_­order​::​seq_­cst operation, then X precedes B in S; and

(4.4) if a memory_­order​::​seq_­cst fence X happens before A and B happens before a memory_­order​::​seq_­cst fence Y, then X precedes Y in S.


回答1:


Why was "strongly happens before" introduced? Intuitively, what's its difference and relation with "happens before"?

Brace yourself for "simply happens-before" as well! Take a look at this current snapshot of cppref https://en.cppreference.com/w/cpp/atomic/memory_order

It seems "simply happens-before" is added in C++20.

Simply happens-before

Regardless of threads, evaluation A simply happens-before evaluation B if any of the following is true:

1) A is sequenced-before B

2) A synchronizes-with B

3) A simply happens-before X, and X simply happens-before B

Note: without consume operations, simply happens-before and happens-before relations are the same.

So Simply-HB and HB are the same except for how they handle consume operations. See HB

Happens-before

Regardless of threads, evaluation A happens-before evaluation B if any of the following is true:

1) A is sequenced-before B

2) A inter-thread happens before B

The implementation is required to ensure that the happens-before relation is acyclic, by introducing additional synchronization if necessary (it can only be necessary if a consume operation is involved, see Batty et al)

How do they differ with regard to consume? See Inter-Thread-HB

Inter-thread happens-before

Between threads, evaluation A inter-thread happens before evaluation B if any of the following is true

1) A synchronizes-with B

2) A is dependency-ordered before B

3) ...

...

An operation that is dependency ordered (i.e. uses release/consume) is HB but not necessarily Simply-HB.

Consume is more relaxed than acquire, so if I understand correctly, HB is more relaxed than Simply-HB.

Strongly happens-before

Regardless of threads, evaluation A strongly happens-before evaluation B if any of the following is true:

1) A is sequenced-before B

2) A synchronizes with B, and both A and B are sequentially consistent atomic operations

3) A is sequenced-before X, X simply happens-before Y, and Y is sequenced-before B

4) A strongly happens-before X, and X strongly happens-before B

Note: informally, if A strongly happens-before B, then A appears to be evaluated before B in all contexts.

Note: strongly happens-before excludes consume operations.

So a release/consume operation cannot be Strongly-HB.

Release/acquire can be HB and Simply-HB (because release/acquire synchronizes-with) but is not necessarily Strongly-HB. Because Strongly-HB specifically says that A must synchronize-with B AND be a Sequentially Consistent operation.

                            Is happens-before guaranteed?

                        HB             Simply-HB          Strongly-HB

relaxed                 no                 no                 no
release/consume        yes                 no                 no      
release/acquire        yes                yes                 no
S.C.                   yes                yes                yes

What does the "A appears to be evaluated before B in all contexts" in the note mean?

All contexts: All threads / all CPUs see (or "will eventually agree on") the same order. This is the guarantee of sequential consistency--a global total modification order of all variables. Acquire/release chains only guarantee perceived modification order for threads participating in the chain. Threads outside the chain are theoretically allowed to see a different order.

I do not know why Strongly-HB and Simply-HB were introduced. Maybe to help clarify how to operate around consume? Strongly-HB has a nice properties--if one thread observes A strongly-happens-before B, it knows all threads will observe the same thing.

The history of consume:

Paul E. McKenney is responsible for consume being in the C and C++ standards. Consume guarantees ordering between pointer assignment and the memory it points to. It was invented because of the DEC Alpha. The DEC Alpha could speculatively dereference a pointer, thus it also had a memory fence to prevent this. The DEC Alpha is no longer made and no processors today have this behavior. Consume is intended to be very relaxed.




回答2:


Seems like "strongly happens before" means:

  1. fully / completely
  2. with absolute certainty
  3. the only possible way of things to happen

Apparently there were cases when "happens before" was misread or misrepresented for something a bit different, hence the need for the reinforcement with "strongly".



来源:https://stackoverflow.com/questions/58986135/what-does-strongly-happens-before-mean

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!