Go 同步原语原子包

Go 同步原语原子包,go,Go,Go have Once原语中的同步包。Do()方法实现了 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

Go have Once原语中的同步包。Do()方法实现了

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()
    }
}
为什么我不能使用这个方法的其他版本

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()
    }
}
如果o.done==1,则不能保证在
中读取
done
。在这些情况下,程序的行为是未定义的。有很多方法会出错——例如,您可能会读取另一个goroutine中写入的部分值

修改由多个goroutine同时访问的数据的程序必须序列化此类访问

要序列化访问,请使用通道操作或其他同步原语(如
sync
sync/atomic
包中的原语)保护数据


您的版本存在数据竞争。结果未定义。比如说,

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)
}
输出:

$ 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
$ 

请参阅。

,因为这将在不同步的情况下并发读取done字段,这是未定义的行为。