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.

Reply via email to