On Wed, Oct 12, 2016 at 9:39 AM, Konstantin Khomoutov <flatw...@users.sourceforge.net> wrote: > On Wed, 12 Oct 2016 07:36:15 -0500 > John Souvestre <j...@souvestre.com> wrote: > >> Interesting. I didn’t realize that thread was live again. I thought >> that this one put it to rest. >> https://groups.google.com/forum/#!msg/golang-nuts/7EnEhM3U7B8/nKCZ17yAtZwJ >> >> I don’t know for sure, but I imagine that Russ’ statement about >> atomics was mainly concerning synchronization – which Go’s >> sync/atomic operations provide. And I would certainly agree. > > I surely maybe completely wrong in interpreting what Henrik Johansson > tries to express but I think I share confusion with him on this point so > let me try to express it in different words. > > I assume you're correct that on today's popular H/W architectures > functions of the sync/atomic package emit a memory barrier and hence > stuff like > > // goroutine 1 > data = 42 > atomic.StoreInt32(&ready, 1) > > // goroutine 2 > for { > if atomic.CompareAndSwapInt32(&ready, 1, 0) { > break > } > runtime.Gosched() > } > if data != 42 { > panic("broken") > } > > works because those memory barriers are full—and hence "global". > > But the crucial point is that this is an implicit and unspecified > (as in "not in the spec") property of those operations. > > I, for one, can't see why atomic.Store() has to issue a full memory > barrier at all: as I understand the sole guarantee of its "atomicity" > property is that no reader of the affected memory region will observe a > so-called "partial update" when atomic.Store() performs that update. > Now suppose some (future or existing) H/W arch would allow maintaining > this "readers see no partial update" invariant while not issuing a > memory fence. In this case the value read from the "data" variable in > the second goroutine in the example above may legitimately be != 42. > To rephrase, I fail to see how a pair of store/CAS functions from > sync/atomic enforce the "happens before" relationship on anything > except the precise memory region under a variable they operate on. > > To quote the Wikipedia article on memory barriers [1]: > > | Some architectures, including the ubiquitous x86/x64, provide several > | memory barrier instructions including an instruction sometimes called > | "full fence". A full fence ensures that all load and store operations > | prior to the fence will have been committed prior to any loads and > | stores issued following the fence. Other architectures, such as the > | Itanium, provide separate "acquire" and "release" memory barriers > | which address the visibility of read-after-write operations from the > | point of view of a reader (sink) or writer (source) respectively. > | Some architectures provide separate memory barriers to control > | ordering between different combinations of system memory and I/O > | memory. When more than one memory barrier instruction is available it > | is important to consider that the cost of different instructions may > | vary considerably. > > So, above I was actually referring to those «separate "acquire" and > "release" memory barriers». > > Could you please clear this confusion up for me?
I think I've lost the context here, but: 1) I agree that sync/atomic should ideally have more details in the memory model (https://golang.org/issue/5045); 2) atomic.LoadXX is either a full barrier or a load-acquire, and atomic.StoreXX is either a full barrier or a store-release. EIther way, goroutine 2 will see the value assigned to data in goroutine 1. Ian -- 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.