在golang中分配指针原子?

时间:2014-01-30 03:49:49

标签: concurrency go atomic

在go中分配指针原子吗?

我是否需要在锁定中指定指针?假设我只想将指针指向nil,并希望其他线程能够看到它。我知道在java中我们可以使用volatile。但是没有任何不稳定因素。

感谢。

3 个答案:

答案 0 :(得分:16)

唯一可以保证是原子的东西是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))

}

答案 1 :(得分:6)

由于规范未指定您应该假设它不是。即使它目前是原子的,它也可能在没有违反规范的情况下发生变化。

答案 2 :(得分:2)

除了Nick's answer之外,从Go 1.4开始,还有atomic.Value类型。它的Store(interface)Load() interface方法负责unsafe.Pointer的转换。

简单的example

package main

import (
    "sync/atomic"
)

type stats struct{}

type myType struct {
    stats atomic.Value
}

func main() {
    var t myType
    
    s := new(stats)
    
    t.stats.Store(s)
    
    s = t.stats.Load().(*stats)
}

或者是Go playground上的文档的更扩展示例。