My argument is made without reference to registers, liveness,
inlining, or any of that.

The memory model defines certain behavior of mutexes (intuitively,
it's how you think they would work) and sync/atomic defines how
StoreUint32 behaves (it's some atomic version of *o.done = 1).

(There are details of how atomic ops interact with the memory model
that haven't been formalized yet -- that's
https://github.com/golang/go/issues/5045 -- but I don't believe that
even matters for this.)

By following the memory model rules, it seems clear that there's a
happens-before total ordering of all the reads and writes of o.done
*within the mutex*, and therefore the read ('if o.done == 0') must
give the value of the previous write. Future compiler changes must
preserve these properties, even if it's true that they only hold by
accident today.

>>
>> atomic.StoreUint32(&o.done, 1)
>
> Taking the address of the done field in the o object will have no
> impact on the value of o.done potentially cached in a register. If
> this code is inlined into its caller then the registerised copy of
> o.done may be consulted again without respect to the atomic load
> earlier in the function.
>
> This is probably not happening today because this function is not a
> leaf function and is not eligible for inlining at the default
> settings. The correctness of the function is relying on unspecified
> compiler behaviour.

Just to make sure I understand your claim: would you say that this
program ought to be allowed to print either 1 or 2?
https://play.golang.org/p/fdf8VeJ98Jv

-- 
You received this message because you are subscribed to the Google Groups 
"golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to golang-nuts+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to