package main
import (
"fmt"
"sync"
"sync/atomic"
)
type atomCounter struct {
val int64
}
Это структура для хранения требуемой атомарной переменной int64.
func (c *atomCounter) Value() int64 {
return atomic.LoadInt64(&c.val)
}
Это вспомогательная функция, которая возвращает текущее значение атомарной переменной int64, используя atomic.LoadInt64().
func main() {
X := 100
Y := 4
var waitGroup sync.WaitGroup
counter := atomCounter{}
for i := 0; i < X; i++ {
Мы создаем множество горутин, которые изменяют общую переменную. Как указывалось ранее, благодаря использованию пакета atomic для работы с общей переменной мы получаем простой способ избежать состояний гонки при изменении ее значения.
waitGroup.Add(1)
go func(no int) {
defer waitGroup.Done()
for i := 0; i < Y; i++ {
atomic.AddInt64(&counter.val, 1)
}
Функция atomic.AddInt64() безопасно изменяет значение поля val структуры counter.
}(i)
}
waitGroup.Wait()
fmt.Println(counter.Value())
}
При выполнении atomic.go в ходе проверки состояний гонки мы получаем такой вывод:
$ go run -race atomic.go
400
Таким образом, атомарная переменная изменяется несколькими горутинами без каких-либо проблем.
В следующем подразделе показано, как с помощью горутин совместно использовать память.