Go RWMutex 仍然会引发竞争条件吗?
Go RWMutex still raises race condition?
我有一个看似无辜的包,它只是制作一个切片并用 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
时,它 returns(除其他外):
==================
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.Append
的 i
与 for 循环同时递增的 i
相同。
我还建议 运行 go vet
以在将来捕获此类错误。有关更多信息,在 Go FAQ 中有一个关于此问题的条目,该条目更详细:https://golang.org/doc/faq#closures_and_goroutines
我有一个看似无辜的包,它只是制作一个切片并用 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
时,它 returns(除其他外):
==================
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.Append
的 i
与 for 循环同时递增的 i
相同。
我还建议 运行 go vet
以在将来捕获此类错误。有关更多信息,在 Go FAQ 中有一个关于此问题的条目,该条目更详细:https://golang.org/doc/faq#closures_and_goroutines