我需要在多个go例程中更新共享对象的计时器。但它最终会遇到竞争条件。我无法使用锁定等待频道,因为所有其他例程都必须等待。
package main
import(
"time"
"math/rand"
)
type R struct {
timer *time.Timer
//other fields
}
func f(done chan bool,r *R){
r.timer =time.NewTimer(time.Millisecond * time.Duration(1000 + rand.Intn(2)))
//some code simultaneously accessing other fields of shared object r, cannot put a lock here
<-r.timer.C
done <- true
}
func main(){
done := make(chan bool , 5)
var r *R
var t *time.Timer
r = &R{timer:t}
for i:=0;i<5;i++{
go f(done,r)
}
for i:=0;i<5;i++{
<-done
}
}
当我使用
运行时 go run -race thread.go
它给出了
==================
WARNING: DATA RACE
Write by goroutine 5:
main.f()
usr/local/gocode/thread.go:12 +0x69
Previous write by goroutine 4:
main.f()
usr/local/gocode/thread.go:12 +0x69
Goroutine 5 (running) created at:
main.main()
usr/local/gocode/thread.go:25 +0xd3
Goroutine 4 (running) created at:
main.main()
usr/local/gocode/thread.go:25 +0xd3
==================
并挂起
任何帮助都会有用
答案 0 :(得分:2)
这里有一个设计问题 - 你有一个R对象,它有一个共享实例,但是每个goroutine都会创建一个本地的新计时器。在我看来,每个goroutine需要一个本地计时器,而不是在所有计时器之间共享计时器,它只是没有意义。
如果您像这样重写代码:
type R struct {
//other fields
Foo string
Bar interface{}
}
func f(done chan bool, r *R) {
timer := time.NewTimer(time.Millisecond * time.Duration(1000+rand.Intn(2)))
//some code simultaneously accessing other fields of shared object r, cannot put a lock here
<-timer.C
done <- true
}
计时器应该是goroutine的本地计时器,并且你没有竞争条件,至少对于计时器访问而言。
请注意,仍然必须使用互斥锁保护对共享对象的其他字段的访问权限,否则您将遇到同样的问题。