cplusplus / CWG

Core Working Group
23 stars 7 forks source link

It is underspecified whether the user-implemented `atomic` can establish a synchronous relationship #424

Closed xmh0511 closed 1 year ago

xmh0511 commented 1 year ago

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

This is an issue on SO https://stackoverflow.com/questions/77130842/can-the-operation-of-the-user-implemented-atomic-by-assemble-establish-a-synchro/77131137?noredirect=1#comment135974198_77131137

Consider the following pseudo-code

struct SpinLock{
   bool* ptr
   void lock(){
      // mov eax, false
      // new_val = true
      while /* lock cmpxchg [ptr], new_val */{  // until *ptr == false
      }
   }
   void unlock(){
     // mov [ptr], false
   }
};

We strictly define the "happen before" relationship in [intro.races] p10, and in this case, we hope the prior unlock can synchronize with the latter lock, however, except in [thread] subclause, which explicitly specifies which operations are synchronous, the current wording didn't give any room to implementation to specify the synchronous relationship, which in turn can establish the "happen before" relationship.

Does it mean we can never implement our spinlock in the standard C++?

frederick-vs-ja commented 1 year ago

Does it mean we can never implement our spinlock in the standard C++?

I believe the answer is intendedly yes. Otherwise, there needs to be some operations implementable in C++98 (which knows nothing about multithreading) "promoted" to atomic operations, which is likely undesired.

jensmaurer commented 1 year ago

A conforming implementation can always promote certain operations to have atomic synchronization effects (e.g. by turning all stores into atomic stores), but that's not something the standard requires or prescribes. However, that's not something the standard guarantees, thus such code will be non-portable. (You already hint at the non-portability by using assembly language in your example.)

I can't see a defect here; if you wish to establish some standard-level means to say "this piece of assembly has these synchronization effects", please submit a paper to WG21, for attention of its SG1 / EWG subgroups.

xmh0511 commented 1 year ago

A conforming implementation can always promote certain operations to have atomic synchronization effects (e.g. by turning all stores into atomic stores), but that's not something the standard requires or prescribes. However, that's not something the standard guarantees, thus such code will be non-portable.

One thing could you please confirm here? Is this implementation-defined behavior or UB? I didn't see the standard has a wording that specifies the synchronous relationships are otherwise implementation-defined other than those defined in the standard library.

jensmaurer commented 1 year ago

This is just part of the abstract machine -> concrete machine mapping that every implementation does. Your concrete machine can exhibit stricter synchronization than is guaranteed in the abstract machine.

I can't see how being stricter would be undefined behavior. I can't see why an implementation would be required to document what it does, thus it's not implementation-defined, either. It's simply something that is not specified.

xmh0511 commented 1 year ago

I can't see how being stricter would be undefined behavior. I can't see why an implementation would be required to document what it does, thus it's not implementation-defined, either. It's simply something that is not specified.

This is the divergence here. At best, [dcl.asm] p1 says this is the implementation-defined behavior

The asm declaration is conditionally-supported; any restrictions on the balanced-token-seq and its meaning are implementation-defined.

Things get unclearer if lock and unlock are implemented in .S file and linked together. Anyway, the standard seems not to say the behavior is unspecified.

[intro.abstract] p3

Certain other aspects and operations of the abstract machine are described in this document as unspecified (for example, order of evaluation of arguments in a function call ([expr.call])).

The above aspects are not described in the document, I think.