Go 1.17中使用atomic.SwapPointer修改指针接收者值是否安全?
结论
你的代码既不具备并发安全性,也无法实现你预期的指针替换效果,和Go 1.17的寄存器传参机制没有关联,问题根源在于你对Go指针接收者的传递逻辑理解有误。
问题原因
- 指针接收者
this本质是方法的局部参数变量,你拿到的&this是这个局部变量的内存地址,不是调用方持有的原始指针变量的地址。不管参数是栈传递还是寄存器传递,this都是调用方传入指针的副本,你修改这个副本的取值,完全不会影响外部的原始指针变量,atomic.SwapPointer操作本质是在修改一个方法执行结束后就会被丢弃的临时变量,没有任何实际意义。 - 可以用下面的示例验证效果:
运行后可以明确看到外部的type A struct { Val int } func (this *A) Replace(a *A) { atomic.SwapPointer((*unsafe.Pointer)(unsafe.Pointer(&this)), unsafe.Pointer(a)) fmt.Println("方法内this值:", this.Val) // 这里打印的是新a的Val } func main() { a1 := &A{Val: 1} a2 := &A{Val: 2} a1.Replace(a2) fmt.Println("方法外a1值:", a1.Val) // 这里还是打印1,完全没被修改 }a1没有任何变化,你的修改逻辑完全无效。
正确实现方案
如果要实现并发安全的指针替换,需要将需要被替换的指针变量作为结构体的成员存储,直接对该成员做原子操作:
import "sync/atomic" import "unsafe" type A struct { Val int } type AHolder struct { // 专门存储需要被原子替换的*A指针,必须用unsafe.Pointer类型保证原子操作的合法性 ptr unsafe.Pointer } func NewAHolder(init *A) *AHolder { return &AHolder{ ptr: unsafe.Pointer(init), } } func (h *AHolder) Replace(newA *A) { // 其他业务逻辑 // ... // 直接操作结构体持有的ptr成员,不是操作接收者副本 atomic.SwapPointer(&h.ptr, unsafe.Pointer(newA)) } // 读取的时候也必须用原子操作,保证并发可见性 func (h *AHolder) Get() *A { return (*A)(atomic.LoadPointer(&h.ptr)) }
关于Go 1.17寄存器传参的说明
寄存器传参只是改变了参数的存储位置,没有改变Go语言「所有参数都是值传递」的核心规则,指针接收者作为参数同样是值拷贝,这个机制和你的问题没有任何关联。
内容的提问来源于stack exchange,提问作者nobody
相关产品推荐
相关产品推荐

