【问题标题】:Go RWMutex still raises race condition?Go RWMutex 仍然会引发比赛条件?
【发布时间】:2018-03-21 02:58:32
【问题描述】:

我有一个看似无辜的包,它只是切片并用 RWMutex 保护它。但是,当我运行它时,它仍然抱怨竞争条件。我究竟做错了什么? (playground)

type Ids struct {
    e []int64
    sync.RWMutex
}

func (i *Ids) Read() []int64 {
    i.RLock()
    defer i.RUnlock()

    return i.e
}


func (i *Ids) Append(int int64) {
    i.Lock()
    defer i.Unlock()

    i.e = append(i.e, int)
}

func main() {
    t := &Ids{e: make([]int64, 1)}

    for i := 0; i < 100; i++ {
        go func() {
            fmt.Printf("%v\n", t.Read())
        }()

        go func() {
            t.Append(int64(i))
        }()
    }

    time.Sleep(time.Second * 10)
}

当使用-race 运行时,它会返回(除其他外):

==================
WARNING: DATA RACE
Read at 0x00c4200a0010 by goroutine 7:
  main.main.func2()
      .../main.go:38 +0x38

Previous write at 0x00c4200a0010 by main goroutine:
  main.main()
      .../main.go:32 +0x197

Goroutine 7 (running) created at:
  main.main()
      .../main.go:37 +0x173
==================

【问题讨论】:

    标签: go concurrency mutex race-condition


    【解决方案1】:

    您正在多个 goroutine 中捕获相同的变量 i

    解决此问题的一种方法是修改您的主 for 循环,如下所示:

    for i := 0; i < 100; i++ {
        i := i  # look here
        go func() {
            fmt.Printf("%v\n", t.Read())
        }()
    
        go func() {
            t.Append(int64(i))
        }()
    }
    

    这将确保您在 for 循环的每次迭代中捕获第二个 goroutine 的闭包中的不同变量。在您的示例中,传递给 t.Appendi 与由 for 循环同时递增的 i 相同。

    我还建议在将来运行go vet 以捕获此类错误。有关更多信息,请参阅 Go 常见问题解答中有关此问题的条目,该条目更详细:https://golang.org/doc/faq#closures_and_goroutines

    【讨论】:

    • 可以支持go vet的推荐,gometalinter也很实用。另一种流行的解决方法是将i 作为参数传递给go func
    猜你喜欢
    • 2021-03-21
    • 1970-01-01
    • 1970-01-01
    • 2021-04-14
    • 1970-01-01
    • 1970-01-01
    • 2013-11-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多