golang的copyCheck.check如何检测对象复制?
// copyChecker holds back pointer to itself to detect object copying.
type copyChecker uintptr
func (c *copyChecker) check() {
if uintptr(*c) != uintptr(unsafe.Pointer(c)) &&
!atomic.CompareAndSwapUintptr((*uintptr)(c), 0, uintptr(unsafe.Pointer(c))) &&
uintptr(*c) != uintptr(unsafe.Pointer(c)) {
panic("sync.Cond is copied")
}
}
创建它时,它将其值设置为自己的地址。要检查它是否已被复制,它会将其地址与存储的值进行比较。如果它被复制,它的地址将不同,但值将相同,因此它将不再指向自身。
好的,首先看看copyChecker
是什么:它是一个uintptr
。因此,有一个关键点:声称在首次使用后不得复制该物品。每个“use”(导出的方法)都从调用对象的checker
开始。第一次调用Cond
类型的方法之一时,它会隐藏其checker
的地址。将来的任何使用都将检查检查器对象是否在存储的地址。如果你复制它,副本将必须有一个不同的地址,这将是恐慌。
实际检查的工作原理:
第一次被击中时,c
为零,所以它与c
实际上的地址不同。有一个原子交换,当且仅当当前值为零时才在c
的地址交换,并确保这种情况以原子方式发生。如果c
为零或c
的值不是自己的地址,则第一次比较可以成功。比较确保它不为零。因此,当第三次比较发生时,该值为零并且此后已设置为其当前地址(并且它们不会不相等),或者该值首先不为零。如果该值不为零,并且也与当前地址不同,则表示此Cond
是通过获取已使用的Cond
并将其复制到新地址而制作的。