3

The code in sync/atomic.once.go is :

func (o *Once) Do(f func()) {
        if atomic.LoadUint32(&o.done) == 1 { //A
        //if o.done == 1 {
            return
        }
        // Slow-path.
        o.m.Lock()
        defer o.m.Unlock()
        if o.done == 0 {
            f()
            atomic.CompareAndSwapUint32(&o.done, 0, 1) //B
            //o.done = 1
        }
    }

I don't think the two 'atomic-style' code A,B above is necessary or useful. I think the lock is enough, and it could be ok if A,B are not atomic style. I must miss something, please be kind to tell me the purpose of the code A,B. Thank you.

hardPass
  • 19,033
  • 19
  • 40
  • 42

1 Answers1

4

The original is correct. The reason is that the Go Memory Model says, that without synchronization (if o.done == 1) the changes to o.done might not be observed at all.

zzzz
  • 87,403
  • 16
  • 175
  • 139