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) {
  if data != 42 {

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.

Reply via email to