cplusplus / CWG

Core Working Group
23 stars 7 forks source link

[intro.races] p6 Is "synchronize with" an enclosed concept in the standard #484

Closed xmh0511 closed 6 months ago

xmh0511 commented 6 months ago

Full name of submitter (unless configured in github; will be published with the issue): Jim X

Suppose that a certain platform provides a paired function lock and unlock, which is the only way provided by that platform to protect data from data race. However, [intro.races] p10 says:

An evaluation A happens before an evaluation B (or, equivalently, B happens after A) if:

  • [...]
  • A inter-thread happens before B.

Across two threads, the "happens-before" should be established by

An evaluation A inter-thread happens before an evaluation B if

  • A synchronizes with B, or

This remains an issue that whether A synchronizes with B can only be specified by the C++ standard, that is it's an enclosed concept defined in the standard. Or, it is a common concept that can be specified by other implementation?

This meaning is vague in the standard. I think the intent should be the latter? Otherwise, it would mean any platform that is not covered by the standard library wouldn't have A happens before B when acrossing mutliple threads, even though the platform provides the infrastructure, becuase saying A synchronizes with B is the power of the interpretation of the standard.

Suggested Resolution

Besides those operations defined in the standard library, certain library calls synchronize with other library calls performed by another thread, which is implementation-defined.

Without giving the room that implementations can define which operation synchronizes with another operation, it is hard to says whether the C++ standard contains something like "it is forbidden for anyone but the standard to define which operation 'synchornizes with' another".

frederick-vs-ja commented 6 months ago

"Synchronize with" should be considered multifold - implementations can (and probably already) define their own meanings of the synchronize-with relationship. It seems that the standard doesn't need to collapse different meanings of "synchronize with" together.

xmh0511 commented 6 months ago

It seems that the standard doesn't need to collapse different meanings of "synchronize with" together.

However, preventing data race for non-atomic objects by using the synchronization operations is based on happens-before as per [intro.races] p21 and [intro.races] p13

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.

Between two threads, Whether A happens before B is determined by whether A synchronizes with B, so this means whether operations provided by implementations can establish happens-before is determined whether the implementation defined "Synchronize with" is the same with what the standard says. That is, if the "Synchronize with" is different from what the standard says, then "happen-before" does not apply to these operations provided by implementations, then the non-atomic object protected by these operations would result in UB.

frederick-vs-ja commented 6 months ago

That is, if the "Synchronize with" is different from what the standard says, then "happen-before" does not apply to these operations provided by implementations, then the non-atomic object protected by these operations would result in UB.

It's OK for the standard to say such operations result in UB, which still allows implementations providing stronger guarantees consistent to their meanings of "synchronize with". (Multithreading is currently outside of constant evaluation so no requirement is imposed to implementations if UB happens.)

xmh0511 commented 6 months ago

It's OK for the standard to say such operations result in UB, which still allows implementations providing stronger guarantees

Well, so we agree that using the functions provided by implementations to prevent data race as if these operations were synchronization is an undefined behavior because it violates [intro.races] p13, from the POV of the standard, the functions are not synchronization so they cannot be "happens-before".

The behavior is merely strongly guaranteed by implementations but it is indeed UB from the POV of the standard.

jensmaurer commented 6 months ago

I'm not seeing a defect in the wording here.