为了账号安全,请及时绑定邮箱和手机立即绑定

了解戈鲁丁同步

了解戈鲁丁同步

Go
www说 2022-09-05 17:59:23
我试图了解golang通道和同步。当我使用种族检测器运行我的程序时,它会导致种族检测。我的程序:func main() {    ch := make(chan int)    done := make(chan struct{})    wg := sync.WaitGroup{}    go func() {        defer close(ch)        defer close(done)        wg.Wait()        done <- struct{}{}    }()    for i := 0; i < 5; i++ {        x := i        wg.Add(1)        go func() {            defer wg.Done()            fmt.Println("Value: ", x)            ch <- x        }()    }    loop:    for {        select {        case i := <-ch:            fmt.Println("Value: ", i)        case <- done:            break loop        }    }}比赛检测报告:==================WARNING: DATA RACEWrite at 0x00c000020148 by goroutine 7:  internal/race.Write()      /home/linuxbrew/.linuxbrew/Cellar/go/1.16.5/libexec/src/internal/race/race.go:41 +0x125  sync.(*WaitGroup).Wait()      /home/linuxbrew/.linuxbrew/Cellar/go/1.16.5/libexec/src/sync/waitgroup.go:128 +0x126  main.main.func1()      /home/reddy/code/github.com/awesomeProject/prod.go:106 +0xc4Previous read at 0x00c000020148 by main goroutine:  internal/race.Read()      /home/linuxbrew/.linuxbrew/Cellar/go/1.16.5/libexec/src/internal/race/race.go:37 +0x206  sync.(*WaitGroup).Add()      /home/linuxbrew/.linuxbrew/Cellar/go/1.16.5/libexec/src/sync/waitgroup.go:71 +0x219  main.main()      /home/reddy/code/github.com/awesomeProject/prod.go:112 +0x124Goroutine 7 (running) created at:  main.main()      /home/reddy/code/github.com/awesomeProject/prod.go:103 +0x104==================我无法弄清楚这里出了什么问题。我的分析:wg.Add(1)正在递增计数器wg.Done()在 goroutine 的末尾调用,这会递减计数器ch <- x这应该是一个阻塞调用,因为它是非缓冲通道循环应该迭代,直到完成通道有一些消息,当计数器变为零时发生,即所有5个goroutines都发布了消息waitgroup一旦计数器变为零,goroutine将恢复并完成被调用,一旦消息在主循环中被消耗,它就会中断循环并应优雅地退出。wg
查看完整描述

1 回答

?
肥皂起泡泡

TA贡献1829条经验 获得超6个赞

该程序在调用wg之间有一场竞赛。添加并调用 wg。等等。这些调用可以按任何顺序发生。在调用 之前,调用 时不等待任何 goroutines。wg.Waitwg.Waitwg.Add


通过在启动调用 的 goroutine 之前将调用移动到 进行修复。此更改可确保在调用 之前进行调用。wg.Addwg.Waitwg.Addwg.Wait


for i := 0; i < 5; i++ {

    x := i

    wg.Add(1)

    go func() {

        defer wg.Done()

        fmt.Println("Value: ", x)

        ch <- x

    }()

}


go func() {

    defer close(ch)

    defer close(done)

    wg.Wait()

    done <- struct{}{}

}()

该类型具有在竞赛检测器下运行时检查此错误的代码(建模读取,建模写入)。WaitGroup


通过在关闭时中断主 goroutine 中的循环来简化代码。不需要该通道。chdone


ch := make(chan int)

wg := sync.WaitGroup{}


for i := 0; i < 5; i++ {

    x := i

    wg.Add(1)

    go func() {

        defer wg.Done()

        fmt.Println("Value: ", x)

        ch <- x

    }()

}


go func() {

    wg.Wait()

    close(ch)

}()


for i := range ch {

    fmt.Println("Value: ", i)

}


查看完整回答
反对 回复 2022-09-05
  • 1 回答
  • 0 关注
  • 105 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号