Функция atomic.AddInt32

Функция atomic.AddInt32 выполняет атомарное сложение указанного значения с 32-битным целым числом. В первый параметр мы передаем указатель на переменную типа int32, которую нужно изменить, во второй параметр мы передаем значение типа int32, которое необходимо прибавить к текущему значению. Функция возвращает новое значение после сложения.

Синтаксис

goatomic.AddInt32(addr *int32, delta int32) int32

Функция атомарно добавляет delta к значению по адресу addr и возвращает обновленное значение. Операция выполняется без блокировок, что делает её более эффективной по сравнению с использованием мьютексов для простых счетчиков.

Пример использования в горутинах

Давайте создадим счетчик, который будет инкрементироваться несколькими горутинами с использованием atomic.AddInt32:

gopackage main

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

func main() {
  var counter int32
  var wg sync.WaitGroup

  for i := 0; i < 10; i++ {
    wg.Add(1)
    go func() {
      defer wg.Done()
      for j := 0; j < 100; j++ {
        atomic.AddInt32(&counter, 1)
      }
    }()
  }

  wg.Wait()
  fmt.Println(counter)
}

Результат выполнения кода:

go1000

В этом примере 10 горутин параллельно инкрементируют счетчик 100 раз каждая. Благодаря использованию atomic.AddInt32, финальное значение всегда будет корректным и равным 1000.

Пример с отрицательным приращением

Функция поддерживает как положительные, так и отрицательные значения для приращения. Давайте создадим счетчик, который будет уменьшаться:

gopackage main

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

func main() {
  var counter int32 = 100
  var wg sync.WaitGroup

  for i := 0; i < 5; i++ {
    wg.Add(1)
    go func() {
      defer wg.Done()
      atomic.AddInt32(&counter, -10)
    }()
  }

  wg.Wait()
  fmt.Println(counter)
}

Результат выполнения кода:

go50

Каждая из 5 горутин уменьшает счетчик на 10, поэтому финальное значение составляет 50. Операция атомарна и безопасна для параллельного использования.

Пример с использованием возвращаемого значения

Функция возвращает новое значение, что позволяет использовать его сразу после обновления:

gopackage main

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

func main() {
  var counter int32 = 5
  var wg sync.WaitGroup
  var results []int32

  for i := 0; i < 3; i++ {
    wg.Add(1)
    go func() {
      defer wg.Done()
      newValue := atomic.AddInt32(&counter, 2)
      results = append(results, newValue)
    }()
  }

  wg.Wait()
  fmt.Println("Counter:", counter)
  fmt.Println("Results:", results)
}

Возможный результат выполнения кода:

goCounter: 11
Results: [7 9 11]

Каждая горутина получает уникальное новое значение счетчика, поскольку операция выполняется атомарно и возвращает результат после обновления.

Смотрите также

  • функцию atomic.AddInt64,
    которая выполняет атомарное сложение для 64-битных целых чисел
  • функцию atomic.LoadInt32,
    которая атомарно загружает значение 32-битного целого числа
  • функцию atomic.StoreInt32,
    которая атомарно сохраняет значение 32-битного целого числа
  • тип atomic.Int32,
    который предоставляет структуру с методами для атомарных операций над int32