在指定GOARCH=amd64
选项并在64位操作系统上运行时,golang中指针的大小值是32位还是64位?
如果它是64位大小,是否在内存中对齐了一个全局指针值8字节,以便原子地执行该指针值的读或写操作?
例如,在下面的代码中,当读取goroutine读取指针时,是否可能仅部分更新全局指针p?
var p *int
void main() {
i := 1
p = &i
go func() {
fmt.Println(*p)
}()
}
我关注的情况是,只有一次写入但是对全局指针值进行多次读取,并且读取指针的旧值并不重要。提前谢谢!
答案 0 :(得分:3)
唯一保证是原子的东西是sync.atomic中的操作。
因此,如果您想确定您需要锁定,例如sync.Mutex或使用其中一个原子基元。我不建议使用原子基元,因为你必须在使用指针的地方使用它们,而且它们很难正确使用。
使用互斥锁就行了 - 你可以定义一个函数来非常容易地锁定当前指针,例如
import "sync"
var secretPointer *int
var pointerLock sync.Mutex
func CurrentPointer() *int {
pointerLock.Lock()
defer pointerLock.Unlock()
return secretPointer
}
func SetPointer(p *int) {
pointerLock.Lock()
secretPointer = p
pointerLock.Unlock()
}
这些函数返回指向其客户端的指针副本,即使更改了主指针也会保持不变。根据您的要求的时间关键程度,这可能是也可能不可接受。它应该足以避免任何未定义的行为 - 垃圾收集器将确保指针始终保持有效,即使程序不再使用指向的内存也是如此。
另一种方法是仅从一个例程执行指针访问,并使用通道来命令该例程进行操作。这将被认为是更惯用的,但可能不适合您的应用程序。
Here is an example展示了如何使用atomic.SetPointer。由于使用了unsafe.Pointer,它相当丑陋。但是unsafe.Pointer强制编译为空,因此运行时成本很小。
import (
"fmt"
"sync/atomic"
"unsafe"
)
type Struct struct {
p unsafe.Pointer // some pointer
}
func main() {
data := 1
info := Struct{p: unsafe.Pointer(&data)}
fmt.Printf("info is %d\n", *(*int)(info.p))
otherData := 2
atomic.StorePointer(&info.p, unsafe.Pointer(&otherData))
fmt.Printf("info is %d\n", *(*int)(info.p))
}