英文:
Multiple go routines waiting for a shared Timer causing race
问题
我有一个要求,需要在多个Go协程中更新共享对象的计时器。但是最终出现了竞争条件。我不能在通道上使用锁进行等待,因为所有其他协程都必须等待。
package main
import(
"time"
"math/rand"
)
type R struct {
timer *time.Timer
//其他字段
}
func f(done chan bool, r *R){
r.timer = time.NewTimer(time.Millisecond * time.Duration(1000 + rand.Intn(2)))
//同时访问共享对象r的其他字段的一些代码,不能在这里加锁
<-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
==================
希望能提供帮助。
英文:
I have a requirement to update timer of a shared object in multiple go routines. But it end up with race condition. I cannot use lock for waiting on the channel because all the other routines will have to wait.
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
}
}
when I run using
go run -race thread.go
it gives
==================
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
==================
and hangs
any help would be useful
答案1
得分: 3
这里存在一个设计问题 - 你有一个 R 对象,并且它有一个共享实例,但是每个 goroutine 都创建了一个新的本地计时器。在我看来,你需要每个 goroutine 都有一个本地计时器,而不是在它们之间共享一个计时器,这样做没有意义。
如果你按照以下方式重写你的代码:
type R struct {
//其他字段
Foo string
Bar interface{}
}
func f(done chan bool, r *R) {
timer := time.NewTimer(time.Millisecond * time.Duration(1000+rand.Intn(2)))
//同时访问共享对象 r 的其他字段的一些代码,不能在这里加锁
<-timer.C
done <- true
}
计时器就变成了每个 goroutine 的本地变量,这样你就没有竞争条件,至少对于计时器的访问来说是如此。
请注意,仍然需要通过互斥锁来保护对共享对象的其他字段的每次访问,否则你会遇到相同的问题。
英文:
There is a design issue here - you have one R object, and it has a shared instance, but every goroutine creates a new timer that is local. Seems to me like you need a local timer per goroutine, and not share that timer between all of them, it just doesn't make sense.
If you rewrite your code like so:
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
}
the timer becomes local to the goroutine as it should be, and you have no race condition, at least for the timer access.
Note that still, ever access to the shared object's other fields must be protected by a mutex or you'll get the same issue.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论