I have a seemingly innocent package that just makes a slice and protects it with a RWMutex. However, when I run it, it still complains about a race condition. What am I doing wrong? ( 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)
}
when run with -race
, it returns (among other things):
==================
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
==================
You are capturing the same variable i
in multiple goroutines.
One way to fix this is to modify your main for loop like so:
for i := 0; i < 100; i++ {
i := i # look here
go func() {
fmt.Printf("%v\n", t.Read())
}()
go func() {
t.Append(int64(i))
}()
}
This will ensure that you capture a different variable in the closure of the second goroutine each iteration of the for loop. In your example, the i
passed to t.Append
was the same i
that was incremented by the for loop concurrently.
I also recommend running go vet
to catch such errors in the future. For more information, there is an entry on this problem in the Go FAQ that goes into more detail: https://golang.org/doc/faq#closures_and_goroutines
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.