Is assigning a pointer atomic in Go?

前端 未结 3 1282
梦谈多话
梦谈多话 2020-12-16 11:16

Is assigning a pointer atomic in Go?

Do I need to assign a pointer in a lock? Suppose I just want to assign the pointer to nil, and would like other threads to be abl

3条回答
  •  旧巷少年郎
    2020-12-16 11:58

    The only things which are guaranteed to be atomic in go are the operations in sync.atomic.

    So if you want to be certain you'll either need to take a lock, eg sync.Mutex or use one of the atomic primitives. I don't recommend using the atomic primitives though as you'll have to use them everywhere you use the pointer and they are difficult to get right.

    Using the mutex is OK go style - you could define a function to return the current pointer with locking very easily, eg something like

    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()
    }
    

    These functions return a copy of the pointer to their clients which will stay constant even if the master pointer is changed. This may or may not be acceptable depending on how time critical your requirement is. It should be enough to avoid any undefined behaviour - the garbage collector will ensure that the pointers remain valid at all times even if the memory pointed to is no longer used by your program.

    An alternative approach would be to only do the pointer access from one go routine and use channels to command that go routine into doing things. That would be considered more idiomatic go, but may not suit your application exactly.

    Update

    Here is an example showing how to use atomic.SetPointer. It is rather ugly due to the use of unsafe.Pointer. However unsafe.Pointer casts compile to nothing so the runtime cost is small.

    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))
    
    }
    

提交回复
热议问题