Тип atomic.Uintptr
Тип atomic.Uintptr представляет собой атомарное беззнаковое целое,
размер которого равен размеру указателя на данной архитектуре (например,
32 бита на 32-битных системах и 64 бита на 64-битных). Этот тип позволяет
выполнять атомарные операции загрузки, сохранения, добавления, обмена и
сравнения с обменом над значениями указателей. В качестве значения
передается целое число, которое может быть интерпретировано как адрес
памяти, а возвращаемое значение представляет собой текущее состояние
счетчика или указателя. Основное назначение atomic.Uintptr —
обеспечить потокобезопасную работу с указателями без использования
тяжеловесных примитивов синхронизации, таких как мьютексы.
Синтаксис
var ptr atomic.Uintptr
ptr.Store(uintptr(addr))
value := ptr.Load()
old := ptr.Swap(uintptr(newAddr))
swapped := ptr.CompareAndSwap(old, uintptr(newAddr))
ptr.Add(uintptr(delta))
Пример
Давайте создадим атомарную переменную типа atomic.Uintptr,
сохраним в нее адрес переменной, а затем загрузим его обратно:
package main
import (
"fmt"
"sync/atomic"
"unsafe"
)
func main() {
var p atomic.Uintptr
x := 42
addr := uintptr(unsafe.Pointer(&x))
p.Store(addr)
loadedAddr := p.Load()
loadedX := *(*int)(unsafe.Pointer(loadedAddr))
fmt.Println(loadedX)
}
Результат выполнения кода:
42
Пример
Теперь выполним атомарное добавление (смещение) к значению указателя. Это может быть полезно при работе с массивами или срезами:
package main
import (
"fmt"
"sync/atomic"
"unsafe"
)
func main() {
var p atomic.Uintptr
arr := []int{10, 20, 30, 40, 50}
base := uintptr(unsafe.Pointer(&arr[0]))
p.Store(base)
// Смещаем указатель на размер одного элемента int
// (на 64-битной системе это обычно 8 байт)
p.Add(unsafe.Sizeof(arr[0]))
newAddr := p.Load()
val := *(*int)(unsafe.Pointer(newAddr))
fmt.Println(val)
}
Результат выполнения кода:
20
Пример
Рассмотрим использование метода CompareAndSwap для атомарной
замены адреса только в том случае, если текущее значение совпадает
с ожидаемым:
package main
import (
"fmt"
"sync/atomic"
"unsafe"
)
func main() {
var p atomic.Uintptr
a := 100
b := 200
addrA := uintptr(unsafe.Pointer(&a))
addrB := uintptr(unsafe.Pointer(&b))
p.Store(addrA)
swapped := p.CompareAndSwap(addrA, addrB)
fmt.Println(swapped)
loaded := p.Load()
val := *(*int)(unsafe.Pointer(loaded))
fmt.Println(val)
}
Результат выполнения кода:
true
200
Смотрите также
-
тип
atomic.Uint64,
который предоставляет атомарные операции над 64-разрядными целыми -
тип
atomic.Pointer,
который обеспечивает атомарную работу с типизированными указателями -
функцию
atomic.AddUintptr,
которая атомарно прибавляет значение к переменной типа uintptr -
функцию
atomic.SwapPointer,
которая атомарно обменивает значение указателя на новое