dongwen2162 2017-01-08 09:41
浏览 133
已采纳

是对golang中的原子指针原子进行读或写操作?

Is the size of a pointer value 32 bits or 64 bits in golang when building with GOARCH=amd64 option specified and running on 64-bit OS?

If it's 64-bit size, is a global pointer value 8-byte aligned in memory so that a read or write operation of that pointer value is carried out atomically?

For example, in the following code, is it possible that the global pointer p is only partially updated when the read goroutine read the pointer?

var p *int

void main() {
    i := 1
    p = &i
    go func() {
        fmt.Println(*p)
    }()
}

The scenario I'm concerning is that there is only one write but multiple reads on a global pointer value, and reading of an old value of the pointer is not important. Thanks in advance!

  • 写回答

1条回答 默认 最新

  • doulian8485 2017-01-08 12:47
    关注

    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.

    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
    ", *(*int)(info.p))
    
        otherData := 2
    
        atomic.StorePointer(&info.p, unsafe.Pointer(&otherData))
    
        fmt.Printf("info is %d
    ", *(*int)(info.p))
    
    }
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 phython如何实现以下功能?查找同一用户名的消费金额合并—
  • ¥15 孟德尔随机化怎样画共定位分析图
  • ¥18 模拟电路问题解答有偿速度
  • ¥15 CST仿真别人的模型结果仿真结果S参数完全不对
  • ¥15 误删注册表文件致win10无法开启
  • ¥15 请问在阿里云服务器中怎么利用数据库制作网站
  • ¥60 ESP32怎么烧录自启动程序
  • ¥50 html2canvas超出滚动条不显示
  • ¥15 java业务性能问题求解(sql,业务设计相关)
  • ¥15 52810 尾椎c三个a 写蓝牙地址