多个go例程等待共享Timer导致竞争

时间:2015-04-21 08:22:26

标签: multithreading go race-condition

我需要在多个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
==================

并挂起

任何帮助都会有用

1 个答案:

答案 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的本地计时器,并且你没有竞争条件,至少对于计时器访问而言。

请注意,仍然必须使用互斥锁保护对共享对象的其他字段的访问权限,否则您将遇到同样的问题。