Тип atomic.Pointer
Тип atomic.Pointer из пакета sync/atomic предоставляет
атомарный указатель на значение любого типа. Он позволяет безопасно
читать и изменять указатель из нескольких горутин без использования
блокировок. Основные методы типа: Load для атомарного чтения,
Store для атомарной записи, Swap для атомарной замены
с возвратом старого значения и CompareAndSwap для условной
атомарной замены.
Синтаксис
var ptr atomic.Pointer[T]
ptr.Store(value)
value := ptr.Load()
old := ptr.Swap(new)
swapped := ptr.CompareAndSwap(old, new)
Пример с Load и Store
Давайте создадим атомарный указатель на строку и выполним атомарные операции чтения и записи:
package main
import (
"fmt"
"sync/atomic"
)
func main() {
var ptr atomic.Pointer[string]
// Store value
initial := "hello"
ptr.Store(&initial)
// Load value
value := ptr.Load()
fmt.Println(*value)
// Store new value
new := "world"
ptr.Store(&new)
// Load new value
value = ptr.Load()
fmt.Println(*value)
}
Результат выполнения кода:
"hello"
"world"
Пример со Swap
Метод Swap атомарно заменяет указатель на новое значение
и возвращает старое:
package main
import (
"fmt"
"sync/atomic"
)
func main() {
var ptr atomic.Pointer[string]
first := "first"
ptr.Store(&first)
// Swap old value with new
second := "second"
old := ptr.Swap(&second)
fmt.Println("Old value:", *old)
fmt.Println("New value:", *ptr.Load())
}
Результат выполнения кода:
"Old value: first"
"New value: second"
Пример с CompareAndSwap
Метод CompareAndSwap выполняет атомарную замену только
если текущее значение указателя совпадает с ожидаемым:
package main
import (
"fmt"
"sync/atomic"
)
func main() {
var ptr atomic.Pointer[string]
current := "current"
ptr.Store(¤t)
expected := "current"
new := "updated"
// This will succeed
swapped := ptr.CompareAndSwap(&expected, &new)
fmt.Println("Swapped:", swapped)
fmt.Println("Value:", *ptr.Load())
// This will fail
expected = "wrong"
new = "another"
swapped = ptr.CompareAndSwap(&expected, &new)
fmt.Println("Swapped:", swapped)
fmt.Println("Value:", *ptr.Load())
}
Результат выполнения кода:
"Swapped: true"
"Value: updated"
"Swapped: false"
"Value: updated"
Пример с использованием в горутинах
Давайте рассмотрим пример безопасного обмена данными между несколькими горутинами с помощью атомарного указателя:
package main
import (
"fmt"
"sync"
"sync/atomic"
"time"
)
func main() {
var ptr atomic.Pointer[string]
var wg sync.WaitGroup
initial := "initial"
ptr.Store(&initial)
// Writer goroutine
wg.Add(1)
go func() {
defer wg.Done()
time.Sleep(100 * time.Millisecond)
updated := "updated"
ptr.Store(&updated)
fmt.Println("Writer: stored new value")
}()
// Reader goroutines
for i := 0; i < 3; i++ {
wg.Add(1)
go func(id int) {
defer wg.Done()
time.Sleep(50 * time.Millisecond)
value := ptr.Load()
fmt.Printf("Reader %d: %s\n", id, *value)
}(i)
}
wg.Wait()
}
Результат выполнения кода:
"Reader 2: initial"
"Reader 0: initial"
"Reader 1: initial"
"Writer: stored new value"
Смотрите также
-
тип
atomic.Value,
который предоставляет атомарное хранилище для значений любого типа -
тип
atomic.Bool,
который предоставляет атомарный булевый тип -
тип
sync.Mutex,
который обеспечивает взаимное исключение для защиты данных -
пакет
go,
который используется для запуска горутин в Go