上卷 程序设计
中卷 标准库
- 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
下卷 运行时
源码剖析
附录
文章来源于网络收集而来,版权归原创者所有,如有侵权请及时联系!
waitgroup
允许有多个等待。
源码剖析
通过 Add/Done
和 Wait
两个计数器来判断状态。
64 32 0 +-------------------+-------------------+-------------------+ | Add/Done counter | Wait counter | Sema | +-------------------+-------------------+-------------------+ |<-------------- state1 --------------->|<---- state2 ----->|
- 正确逻辑:
Add
在Wait
之前,不应并发。
// sync/waitgroup.go type WaitGroup struct { noCopy noCopy // 64-bit value: high 32 bits are counter, // low 32 bits are waiter count. state1 uint64 // [Add/Done, Wait] counter。 state2 uint32 // Sema }
func (wg *WaitGroup) state() (statep *uint64, semap *uint32) { // state1 is 64-bit aligned: nothing to do. return &wg.state1, &wg.state2 }
累加或递减计数,归零时唤醒所有等待。
func (wg *WaitGroup) Done() { wg.Add(-1) } func (wg *WaitGroup) Add(delta int) { // 累加 Add 计数。 statep, semap := wg.state() state := atomic.AddUint64(statep, uint64(delta)<<32) v := int32(state >> 32) // add.count w := uint32(state) // wait.count // 不可能小于零。 if v < 0 { panic("sync: negative WaitGroup counter") } // add.count v == delta,第一次 Add 操作, // wait.count w != 0,先有等待,显然不行! if w != 0 && delta > 0 && v == int32(delta) { panic("sync: WaitGroup misuse: Add called concurrently with Wait") } // 计数未归零,或无人等待,完事。 if v > 0 || w == 0 { return } // This goroutine has set counter to 0 when waiters > 0. // Now there can't be concurrent mutations of state: // - Adds must not happen concurrently with Wait, // - Wait does not increment waiters if it sees counter == 0. // Still do a cheap sanity check to detect WaitGroup misuse. if *statep != state { panic("sync: WaitGroup misuse: Add called concurrently with Wait") } // 上面拦截了 v > 0 的情形。 // 此处只能是最后一次 Done/Add(-1) == 0, // 唤醒所有等待。 *statep = 0 for ; w != 0; w-- { runtime_Semrelease(semap, false, 0) } }
如果计数为零,自然不需要等待。否则,累加等待计数,休眠。
// Wait blocks until the WaitGroup counter is zero. func (wg *WaitGroup) Wait() { statep, semap := wg.state() for { state := atomic.LoadUint64(statep) v := int32(state >> 32) // add.count w := uint32(state) // wait.count if v == 0 { // Counter is 0, no need to wait. return } // Increment waiters count. if atomic.CompareAndSwapUint64(statep, state, state+1) { runtime_Semacquire(semap) return } } }
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论