I see that Ian has already answered your question. > But the crucial point is that this is an implicit and unspecified (as in > "not in the spec") property of those operations.
Although not very verbose, I believe that the Go Memory Model (as I quoted earlier) is the guarantee. And I believe that this statement is meant to cover both CPU and compiler ordering. John John Souvestre - New Orleans LA -----Original Message----- From: Konstantin Khomoutov [mailto:flatw...@users.sourceforge.net] Sent: 2016 October 12, Wed 11:40 To: John Souvestre Cc: 'golang-nuts' Subject: Re: [go-nuts] Re: Go locking and channels much slower than Java equivalent, program spends most of time in sync.(*Mutex).Lock() and sync.(*Mutex).Unlock() 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? 1. https://en.wikipedia.org/wiki/Memory_barrier -- 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.