在Golang中同步基本体原子包

Sync package in golang have Once primitive. Do() method realized that

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

Why i cant use other version this method?

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

The Go memory model does not guarantee that your read of done in if o.done == 1 will proceed atomically. Your program's behaviour is undefined in these circumstances. There are many ways this can go wrong – for example, you may read a partial value being written out in another goroutine.

Programs that modify data being simultaneously accessed by multiple goroutines must serialize such access.

To serialize access, protect the data with channel operations or other synchronization primitives such as those in the sync and sync/atomic packages.

Your version has a data race. The results are undefined. For example,

racer.go:

package main

import (
    "sync"
    "sync/atomic"
    "time"
)

type Once struct {
    m    sync.Mutex
    done uint32
}

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

func main() {
    var once Once

    go once.Do(func() {})
    go once.Do(func() {})

    time.Sleep(1 * time.Second)
}

Output:

$ go run -race racer.go
==================
WARNING: DATA RACE
Read at 0x00c0000a0008 by goroutine 6:
  main.(*Once).Do()
      /home/peter/gopath/src/racer.go:15 +0x47

Previous write at 0x00c0000a0008 by goroutine 5:
  sync/atomic.StoreInt32()
      /home/peter/go/src/runtime/race_amd64.s:229 +0xb
  main.(*Once).Do()
      /home/peter/gopath/src/racer.go:25 +0x9f

Goroutine 6 (running) created at:
  main.main()
      /home/peter/gopath/src/racer.go:31 +0xc4

Goroutine 5 (finished) created at:
  main.main()
      /home/peter/gopath/src/racer.go:30 +0x96
==================
Found 1 data race(s)
exit status 66
$ 

See Go: Data Race Detector.