我想编写一些这样的代码:
var myValue interface{}
func GetMyValue() interface{} {
return atomic.Load(myValue)
}
func StoreMyValue(newValue interface{}) {
atomic.Store(myValue, newValue)
}
似乎我可以使用 loadUintptr(addr *uintptr)(val uintptr) and and storeuintptr(addr *uintptr *uintptr,val uintptr,val uintptr),但我不知道如何在 uintptr 之间转换, unsafe.pointer 和 interface {} 。
如果我这样做:
var V interface{}
func F(v interface{}) {
p := unsafe.Pointer(&V)
atomic.StorePointer(&p, unsafe.Pointer(&v))
}
func main() {
V = 1
F(2)
fmt.Println(V)
}
V 将始终为1
如果我没记错的话,您想要原子值。您可以将其存储和获取值以原子为单位(签名是interface{}
,但应该在其中放置相同的类型)。它像您想做的那样在引擎盖下做一些不安全的指针。
来自文档的样本:
var config Value // holds current server configuration
// Create initial config value and store into config.
config.Store(loadConfig())
go func() {
// Reload config every 10 seconds
// and update config value with the new version.
for {
time.Sleep(10 * time.Second)
config.Store(loadConfig())
}
}()
// Create worker goroutines that handle incoming requests
// using the latest config value.
for i := 0; i < 10; i++ {
go func() {
for r := range requests() {
c := config.Load()
// Handle request r using config c.
_, _ = r, c
}
}()
}
这是一种使用atomic.StorePointer
和atomic.LoadPointer
的方法(基于您的示例):
package main
import (
"fmt"
"sync/atomic"
"unsafe"
)
var addr unsafe.Pointer
func GetMyValue() *interface{} {
return (*interface{})(atomic.LoadPointer(&addr))
}
func StoreMyValue(newValue *interface{}) {
atomic.StorePointer(&addr, unsafe.Pointer(newValue))
}
func main() {
var i interface{}
i = 1
StoreMyValue(&i)
fmt.Println("before:", *GetMyValue())
i = 2
StoreMyValue(&i)
fmt.Println("after", *GetMyValue())
}
游乐场链接
请注意,这不会使您的对象线程安全。只有指针被原子存储/加载。另外,我会避免使用interface{}
,并在可能的情况下更喜欢混凝土类型。
作为使用'any
'(interface{}
)的替代方案,GO 1.19(Q3 2022)在sync/atomic
软件包中带有新类型,使其更易于使用原子值,例如原子。int64和 atomic.Pointer[T]
。
这比使用atomic.StorePointer
更容易。
这来自第50860期。sync/atomic
:添加键入的原子值。
和CL 381317
Pointer[T]
还避免使用Unsafe.pointer在呼叫站点进行转换。
您无法执行此操作。
您将必须用互斥士克保护商店/负载。界面的内部表示未指定语言,并且可能(可能是)可以通过包装原子来处理。