sync.WaitGroup ведет себя не так, как я ожидаю, что мне здесь не хватает?

Учитывая следующее:

package main

import (
    "fmt"
    "sync"
)

func main() {
    n := 100

    var wg sync.WaitGroup
    wg.Add(n)

    x := 0
    for i := 0; i < n; i++ {
        go func() {
            defer wg.Done()
            x++
        }()
    }

    wg.Wait()
    fmt.Println(n, x)
}

Я бы ожидал, что x всегда будет достигать 100 к моменту печати в конце, но иногда печатается до 95. Что мне здесь не хватает?


person Knucklehead    schedule 26.09.2015    source источник


Ответы (2)


Гонка на x. Одним из решений является защита x с помощью мьютекса:

var mu sync.Mutex
var wg sync.WaitGroup
wg.Add(n)

x := 0
for i := 0; i < n; i++ {
    go func() {
        defer wg.Done()
        mu.Lock()
        x++
        mu.Unlock()
    }()
}

wg.Wait()
fmt.Println(n, x)

пример игровой площадки

Я предлагаю запускать детектор гонки всякий раз, когда кто-то находит что-то непонятное в программе Go с более чем одним горутина.

person Cerise Limón    schedule 26.09.2015

используйте метод sync.atomic для атомарного доступа к x.

package main

import (
    "fmt"
    "sync"
    "sync/atomic"
)

func main() {
    n := 100

    var wg sync.WaitGroup
    wg.Add(n)

    var x int32
    for i := 0; i < n; i++ {
        go func() {
            defer wg.Done()
            atomic.AddInt32(&x, 1)
        }()
    }

    wg.Wait()
    fmt.Println(n, x)
}
person Tony Bai    schedule 26.09.2015