doujiaoben28596 2017-01-20 04:21
浏览 54
已采纳

跨并行goroutine共享通道时的Golang竞争条件

I'm writing this example code to teach myself how to share channels across parallel goroutines and I'm hitting a race condition. The program should start as many goroutines as there are available CPUs on the system. The first goroutine to access the bl channel immediately sets the channel to contain false so that no other goroutines can access the loop that ranges over the st channel. The other goroutines should end as the first goroutine that accessed the bl channel reads from the st channel and prints each value.

package main

import (
    "fmt"
    "runtime"
    "strconv"
    "math/rand"
    "time"
    "sync"
)

func main () {
    runtime.GOMAXPROCS(runtime.NumCPU())
    var wg sync.WaitGroup
    st := make(chan string)
    bl := make(chan bool)
    go func() {bl <- true}()

    for i := 0; i < runtime.NumCPU(); i++ {
        wg.Add(1)
        go func(x int) {
            defer wg.Done()
            fmt.Println("me: ", strconv.Itoa(x))

            can := <- bl
            bl <- false

            if can {
                for val := range st {
                    t      := strconv.Itoa(rand.Int()%3)+"s"
                    dur, _ := time.ParseDuration(t)
                    time.Sleep(dur)

                        fmt.Println("time: ", t," i: ", strconv.Itoa(x), val)
                }
            }
            fmt.Println("done: ", strconv.Itoa(x))
        }(i)
    }

    for i := 0; i < 10; i++ {
        st <- "n: "+strconv.Itoa(i)
    }

    wg.Wait()
    close(st)
}

When I run the code, I get the following error:

$ go run share.go 
me:  1
me:  0
me:  2
me:  3
done:  0
done:  2
time:  2s  i:  1 n: 0
time:  1s  i:  1 n: 1
time:  0s  i:  1 n: 2
time:  2s  i:  1 n: 3
time:  2s  i:  1 n: 4
time:  2s  i:  1 n: 5
time:  0s  i:  1 n: 6
time:  2s  i:  1 n: 7
time:  2s  i:  1 n: 8
time:  2s  i:  1 n: 9
fatal error: all goroutines are asleep - deadlock!

goroutine 1 [semacquire]:
sync.runtime_Semacquire(0xc4200701bc)
    /usr/local/go/src/runtime/sema.go:47 +0x30
sync.(*WaitGroup).Wait(0xc4200701b0)
    /usr/local/go/src/sync/waitgroup.go:131 +0x97
main.main()
    /share.go:80 +0x1ef

goroutine 36 [chan receive]:
main.main.func2(0xc4200701b0, 0xc42006e0c0, 0xc42006e060, 0x1)
    /share.go:64 +0x23e
created by main.main
    /share.go:73 +0x127

goroutine 38 [chan send]:
main.main.func2(0xc4200701b0, 0xc42006e0c0, 0xc42006e060, 0x3)
    /share.go:61 +0x1ef
created by main.main
    /share.go:73 +0x127
exit status 2

I'm not sure how to handle this race condition for the bl channel. It seems that the last goroutine is stuck trying to read from the bl channel but there's nothing for it to read because the goroutine before it hasn't inserted false yet. Not sure if my intuition is correct. I placed print lines around the code and that's what seems to be happening at least. I also tried putting an if around the bl channel, but that ended up with the same issue. I also moved bl <- false inside the if can { block, but that didn't work either. How do I fix this?

  • 写回答

1条回答 默认 最新

  • doutuzhuohao6449 2017-01-20 05:43
    关注

    You can send a channel over a channel to protect the single access of a selected value. Only a receiver will do the work and the others will leave when they received the closing signal. See this solution

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 拟通过pc下指令到安卓系统,如果追求响应速度,尽可能无延迟,是不是用安卓模拟器会优于实体的安卓手机?如果是,可以快多少毫秒?
  • ¥20 神经网络Sequential name=sequential, built=False
  • ¥16 Qphython 用xlrd读取excel报错
  • ¥15 单片机学习顺序问题!!
  • ¥15 ikuai客户端多拨vpn,重启总是有个别重拨不上
  • ¥20 关于#anlogic#sdram#的问题,如何解决?(关键词-performance)
  • ¥15 相敏解调 matlab
  • ¥15 求lingo代码和思路
  • ¥15 公交车和无人机协同运输
  • ¥15 stm32代码移植没反应