上卷 程序设计
中卷 标准库
- bufio 1.18
- bytes 1.18
- io 1.18
- container 1.18
- encoding 1.18
- crypto 1.18
- hash 1.18
- index 1.18
- sort 1.18
- context 1.18
- database 1.18
- connection
- query
- queryrow
- exec
- prepare
- transaction
- scan & null
- context
- tcp
- udp
- http
- server
- handler
- client
- h2、tls
- url
- rpc
- exec
- signal
- embed 1.18
- plugin 1.18
- reflect 1.18
- runtime 1.18
- KeepAlived
- ReadMemStats
- SetFinalizer
- Stack
- sync 1.18
- atomic
- mutex
- rwmutex
- waitgroup
- cond
- once
- map
- pool
- copycheck
- nocopy
- unsafe 1.18
- fmt 1.18
- log 1.18
- math 1.18
- time 1.18
- timer
下卷 运行时
源码剖析
附录
文章来源于网络收集而来,版权归原创者所有,如有侵权请及时联系!
atomic
原子操作 意为 “不可被中断的一个或一系列操作”。
原子操作一旦开始,直到结束,中间不会有任何上下文切换(context switch)。处理器通过总线锁定和缓存锁定确保原子性,让多线程不能同一时间访问相同资源。
原子性不可能由软件单独保证 —— 必须有硬件支持,因此和架构相关。在 x86 平台上,CPU 提供在指令执行期间对总线加锁手段。如果在汇编指令前加上 LOCK 前缀,其机器代码就使 CPU 在执行这条指令时锁住总线(或缓存锁定)。如此,同一总线上别的 CPU 暂时不能通过总线访问内存,保证这条指令在多处理器环境中的原子性。
// runtime/internal/atomic/atomic_amd64.s // bool ·Cas64(uint64 *val, uint64 old, uint64 new) // Atomically: // if(*val == old){ // *val = new; // return 1; // } else { // return 0; // } TEXT ·Cas64(SB), NOSPLIT, $0-25 MOVQ ptr+0(FP), BX MOVQ old+8(FP), AX MOVQ new+16(FP), CX LOCK CMPXCHGQ CX, 0(BX) SETEQ ret+24(FP) RET
Value
算是对原子操作的一种包装,不再局限于几种有限的数字类型。
多次存储的数据必须是同一类型。
需要考虑接口参数的额外开销。
// sync/atomic/value.go type Value struct { // 用指针转换为:ifaceWords。 // 当独立字段用:typ, data。 v any } type ifaceWords struct { typ unsafe.Pointer data unsafe.Pointer }
标记第一次写,存入类型信息供后续检查。
// All calls to Store for a given Value must use values of // the same concrete type. Store of an inconsistent type panics, // as does Store(nil). func (v *Value) Store(val any) { // 不能存储 nil。 if val == nil { panic("store of nil value into Value") } // 将 v、&val 转换为 ifaceWords,以读取接口内部信息。 vp := (*ifaceWords)(unsafe.Pointer(v)) vlp := (*ifaceWords)(unsafe.Pointer(&val)) for { typ := LoadPointer(&vp.typ) // 当前 Value 还没有存储类型信息。 if typ == nil { runtime_procPin() // 第一次存储。写入正在存储标记,避免被其他人修改。 if !CompareAndSwapPointer(&vp.typ, nil, unsafe.Pointer(&firstStoreInProgress)) { runtime_procUnpin() continue } // 将 val.typ & .data 写入 Value。 StorePointer(&vp.data, vlp.data) StorePointer(&vp.typ, vlp.typ) runtime_procUnpin() return } // 有人正在进行第一次存储。 if typ == unsafe.Pointer(&firstStoreInProgress) { // First store in progress. Wait. continue } // 检查类型,不一致导致 panic! if typ != vlp.typ { panic("store of inconsistently typed value into Value") } // 修改 Value.data。 StorePointer(&vp.data, vlp.data) return } } var firstStoreInProgress byte
载入操作用存储的数据,重新组装一个接口对象。
func (v *Value) Load() (val any) { vp := (*ifaceWords)(unsafe.Pointer(v)) typ := LoadPointer(&vp.typ) // 从未写入,或第一次写进行中。 if typ == nil || typ == unsafe.Pointer(&firstStoreInProgress) { // First store not yet completed. return nil } data := LoadPointer(&vp.data) // 对返回值 { .typ, .data } 分别赋值, // 组成完整接口对象。 vlp := (*ifaceWords)(unsafe.Pointer(&val)) vlp.typ = typ vlp.data = data return }
至于 CAS,无非是类型和旧值都要一致。
func (v *Value) CompareAndSwap(old, new any) (swapped bool) { if new == nil { panic("compare and swap of nil value into Value") } vp := (*ifaceWords)(unsafe.Pointer(v)) // Value np := (*ifaceWords)(unsafe.Pointer(&new)) op := (*ifaceWords)(unsafe.Pointer(&old)) // 新旧值类型必须一致。 if op.typ != nil && np.typ != op.typ { panic("compare and swap of inconsistently typed values") } for { // 当前 Value 存储的类型。 typ := LoadPointer(&vp.typ) if typ == nil { // 这个 old 肯定不符。 if old != nil { return false } // 首次存储(new)。 runtime_procPin() if !CompareAndSwapPointer(&vp.typ, nil, unsafe.Pointer(&firstStoreInProgress)) { runtime_procUnpin() continue } StorePointer(&vp.data, np.data) StorePointer(&vp.typ, np.typ) runtime_procUnpin() return true } if typ == unsafe.Pointer(&firstStoreInProgress) { // First store in progress. Wait. continue } // 新值类型和已存储类型是否相同。 if typ != np.typ { panic("compare and swap of inconsistently typed value into Value") } // 将当前存储值重新组成接口对象。 data := LoadPointer(&vp.data) var i any (*ifaceWords)(unsafe.Pointer(&i)).typ = typ (*ifaceWords)(unsafe.Pointer(&i)).data = data // 再与旧值(old)进行比较。 if i != old { return false } // CAS 写入新值。 return CompareAndSwapPointer(&vp.data, data, np.data) } }
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论