github.com/ltltlt/go-source-code@v0.0.0-20190830023027-95be009773aa/sync/atomic/value.go (about) 1 // Copyright 2014 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package atomic 6 7 import ( 8 "unsafe" 9 ) 10 11 // A Value provides an atomic load and store of a consistently typed value. 12 // The zero value for a Value returns nil from Load. 13 // Once Store has been called, a Value must not be copied. 14 // 15 // A Value must not be copied after first use. 16 type Value struct { 17 v interface{} 18 } 19 20 // ifaceWords is interface{} internal representation. 21 type ifaceWords struct { 22 typ unsafe.Pointer 23 data unsafe.Pointer 24 } 25 26 // Load returns the value set by the most recent Store. 27 // It returns nil if there has been no call to Store for this Value. 28 func (v *Value) Load() (x interface{}) { 29 vp := (*ifaceWords)(unsafe.Pointer(v)) // 将v解释为*ifaceWords(Value和ifaceWords大小相同) 30 typ := LoadPointer(&vp.typ) 31 if typ == nil || uintptr(typ) == ^uintptr(0) { // 全1代表正在进行第一次存储 32 // First store not yet completed. 33 return nil 34 } 35 data := LoadPointer(&vp.data) 36 xp := (*ifaceWords)(unsafe.Pointer(&x)) // 将x解释为interface{} 37 xp.typ = typ 38 xp.data = data 39 return 40 } 41 42 // Store sets the value of the Value to x. 43 // All calls to Store for a given Value must use values of the same concrete type. 44 // Store of an inconsistent type panics, as does Store(nil). 45 // 一个Value中存的内容必须是相同类型的, 实际上也能实现为可存放不同类型的 46 // 唯一竞态是两个goroutine同时Store, 可能导致类型和数据不匹配, 通过引入type的第三种状态来解决 47 func (v *Value) Store(x interface{}) { 48 if x == nil { 49 panic("sync/atomic: store of nil value into Value") 50 } 51 vp := (*ifaceWords)(unsafe.Pointer(v)) 52 xp := (*ifaceWords)(unsafe.Pointer(&x)) 53 for { 54 typ := LoadPointer(&vp.typ) 55 if typ == nil { 56 // <- 可能在此typ被修改,所以使用CompareAndSwapPointer 57 // Attempt to start first store. 58 // Disable preemption so that other goroutines can use 59 // active spin wait to wait for completion; and so that 60 // GC does not see the fake type accidentally. 61 runtime_procPin() 62 if !CompareAndSwapPointer(&vp.typ, nil, unsafe.Pointer(^uintptr(0))) { 63 runtime_procUnpin() 64 continue 65 } 66 // Complete first store. 67 StorePointer(&vp.data, xp.data) 68 StorePointer(&vp.typ, xp.typ) 69 runtime_procUnpin() 70 return 71 } 72 if uintptr(typ) == ^uintptr(0) { 73 // First store in progress. Wait. 74 // Since we disable preemption around the first store, 75 // we can wait with active spinning. 76 continue 77 } 78 // First store completed. Check type and overwrite data. 79 if typ != xp.typ { 80 panic("sync/atomic: store of inconsistently typed value into Value") 81 } 82 StorePointer(&vp.data, xp.data) 83 return 84 } 85 } 86 87 // Disable/enable preemption, implemented in runtime. 88 func runtime_procPin() 89 func runtime_procUnpin()