为什么这个WaitGroup有时不等待所有goroutines?

Sri*_*har 3 concurrency go

以下代码有时输出2.为什么等待组没有等待所有goroutine完成?

type Scratch struct {
    //sync.RWMutex
    Itch []int
}

func (s *Scratch) GoScratch(done chan bool, j int) error {

    var ws sync.WaitGroup

    if len(s.Itch) == 0 {
            s.Rash = make([]int, 0)
    }
    for i := 0; i < j; i++ {
            ws.Add(1)
            go func (i int) {
                    defer ws.Done()

                   s.Rash = append(s.Rash, i) 
            }(i)
    }
    ws.Wait()
    done<- true
    return nil
}

func main() {
    done := make(chan bool, 3)
    s := &Scratch{}
    err := s.GoScratch(done, 3)
    if err != nil {
            log.Println("Error:%v",err)
    }
    <-done
    log.Println("Length: ", len(s.Rash)) 
}`
Run Code Online (Sandbox Code Playgroud)

奇怪的是我不能用主函数输出2但是当我使用测试用例时它有时输出2.

abh*_*ink 6

您的代码中存在竞争条件.就在这里:

go func (i int) {
    defer ws.Done()
    // race condition on s.Rash access
    s.Rash = append(s.Rash, i) 
}(i)
Run Code Online (Sandbox Code Playgroud)

由于所有goroutine s.Rash同时访问,这可能导致切片更新被覆盖.尝试使用sync.Mutex锁定运行相同的代码以防止这种情况:

// create a global mutex
var mutex = &sync.Mutex{}

// use mutex to prevent race condition
go func (i int) {
    defer ws.Done()
    defer mutex.Unlock() // ensure that mutex unlocks

    // Lock the resource before accessing it
    mutex.Lock()
    s.Rash = append(s.Rash, i) 
}(i)
Run Code Online (Sandbox Code Playgroud)

你可以在这里这里阅读更多相关信息.


Grz*_*Żur 6

如果您使用竞争检测器运行代码

go test -race .
Run Code Online (Sandbox Code Playgroud)

你会在 slice 上找到竞争条件s.Rash