Go RWMutex 仍然会引发竞争条件吗?

标签 go concurrency mutex race-condition

我有一个看似无害的包,它只是制作一个 slice 并使用 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
==================

最佳答案

您正在多个 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 FAQ 中有一个关于此问题的条目,该条目更详细:https://golang.org/doc/faq#closures_and_goroutines

关于Go RWMutex 仍然会引发竞争条件吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49397395/

相关文章:

c++ - 原子类型和线程

go - 使用适用于 Go 的 AWS 开发工具包使用完整 URI 从 S3 下载文件

xml - 使用 Go 的 xml 包编码 DIDL-Lite

c - 您如何查询 pthread 以查看它是否仍在运行?

java - 锁定可变对象 - 为什么它被认为是一种不好的做法?

java - Runnable/Thread 可能的误解

c++ - 什么会导致互斥体行为不端?

go - 结构内部 int 的奇怪行为

google-app-engine - 如何在运行 AppEngine 的 Go 服务器生成的响应中设置 HTTP header ?

c - Linux中的线程并发