了解戈鲁丁同步

我试图了解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 RACE

Write 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 +0xc4


Previous 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 +0x124


Goroutine 7 (running) created at:

  main.main()

      /home/reddy/code/github.com/awesomeProject/prod.go:103 +0x104

==================

我无法弄清楚这里出了什么问题。

我的分析:

  1. wg.Add(1)正在递增计数器

  2. wg.Done()在 goroutine 的末尾调用,这会递减计数器

  3. ch <- x这应该是一个阻塞调用,因为它是非缓冲通道

  4. 循环应该迭代,直到完成通道有一些消息,当计数器变为零时发生,即所有5个goroutines都发布了消息waitgroup

  5. 一旦计数器变为零,goroutine将恢复并完成被调用,一旦消息在主循环中被消耗,它就会中断循环并应优雅地退出。wg


www说
浏览 107回答 1
1回答

肥皂起泡泡

该程序在调用wg之间有一场竞赛。添加并调用 wg。等等。这些调用可以按任何顺序发生。在调用 之前,调用 时不等待任何 goroutines。wg.Waitwg.Waitwg.Add通过在启动调用 的 goroutine 之前将调用移动到 进行修复。此更改可确保在调用 之前进行调用。wg.Addwg.Waitwg.Addwg.Waitfor i := 0; i < 5; i++ {&nbsp; &nbsp; x := i&nbsp; &nbsp; wg.Add(1)&nbsp; &nbsp; go func() {&nbsp; &nbsp; &nbsp; &nbsp; defer wg.Done()&nbsp; &nbsp; &nbsp; &nbsp; fmt.Println("Value: ", x)&nbsp; &nbsp; &nbsp; &nbsp; ch <- x&nbsp; &nbsp; }()}go func() {&nbsp; &nbsp; defer close(ch)&nbsp; &nbsp; defer close(done)&nbsp; &nbsp; wg.Wait()&nbsp; &nbsp; done <- struct{}{}}()该类型具有在竞赛检测器下运行时检查此错误的代码(建模读取,建模写入)。WaitGroup通过在关闭时中断主 goroutine 中的循环来简化代码。不需要该通道。chdonech := make(chan int)wg := sync.WaitGroup{}for i := 0; i < 5; i++ {&nbsp; &nbsp; x := i&nbsp; &nbsp; wg.Add(1)&nbsp; &nbsp; go func() {&nbsp; &nbsp; &nbsp; &nbsp; defer wg.Done()&nbsp; &nbsp; &nbsp; &nbsp; fmt.Println("Value: ", x)&nbsp; &nbsp; &nbsp; &nbsp; ch <- x&nbsp; &nbsp; }()}go func() {&nbsp; &nbsp; wg.Wait()&nbsp; &nbsp; close(ch)}()for i := range ch {&nbsp; &nbsp; fmt.Println("Value: ", i)}
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go