Функция atomic.LoadPointer

Функция atomic.LoadPointer атомарно загружает значение указателя, на которое ссылается аргумент *unsafe.Pointer. Она гарантирует, что чтение выполняется как единая неделимая операция в условиях конкурентного доступа. В первый параметр передается адрес переменной типа unsafe.Pointer, значение которой нужно загрузить. Функция возвращает загруженное значение указателя.

Синтаксис

goatomic.LoadPointer(addr *unsafe.Pointer) unsafe.Pointer

Пример

Давайте создадим указатель на строку и атомарно загрузим его значение:

gopackage main

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

func main() {
  str := "abcde"
  ptr := unsafe.Pointer(&str)

  res := atomic.LoadPointer(&ptr)
  fmt.Println(*(*string)(res))
}

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

go"abcde"

Пример

Рассмотрим атомарное чтение указателя в конкурентной среде с использованием нескольких горутин:

gopackage main

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

func main() {
  var wg sync.WaitGroup
  var ptr unsafe.Pointer
  val := "12345"
  ptr = unsafe.Pointer(&val)

  for i := 0; i < 10; i++ {
    wg.Add(1)
    go func() {
      defer wg.Done()
      res := atomic.LoadPointer(&ptr)
      fmt.Println(*(*string)(res))
    }()
  }

  wg.Wait()
}

Результат выполнения кода (порядок строк может отличаться):

go"12345"
"12345"
"12345"
"12345"
"12345"
"12345"
"12345"
"12345"
"12345"
"12345"

Пример

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

gopackage main

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

func main() {
  var wg sync.WaitGroup
  var ptr unsafe.Pointer
  val1 := "abcde"
  val2 := "12345"
  ptr = unsafe.Pointer(&val1)

  for i := 0; i < 5; i++ {
    wg.Add(1)
    go func() {
      defer wg.Done()
      atomic.StorePointer(&ptr, unsafe.Pointer(&val2))
    }()
  }

  for i := 0; i < 5; i++ {
    wg.Add(1)
    go func() {
      defer wg.Done()
      res := atomic.LoadPointer(&ptr)
      fmt.Println(*(*string)(res))
    }()
  }

  wg.Wait()
}

Результат выполнения кода (порядок строк может отличаться):

go"12345"
"12345"
"12345"
"12345"
"12345"
"abcde"
"abcde"
"abcde"
"abcde"
"abcde"

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

  • функцию atomic.StorePointer,
    которая атомарно записывает значение указателя
  • функцию atomic.SwapPointer,
    которая атомарно заменяет значение указателя и возвращает старое
  • функцию atomic.CompareAndSwapPointer,
    которая атомарно сравнивает и заменяет значение указателя
  • тип atomic.Pointer,
    который предоставляет типизированную атомарную работу с указателями