WaitGroup
從源碼分析 wait group
- Add(delta int) 給WaitGroup的計數器增加一個值,當WaitGroup的計數值減少到零時(這邊的計數是Wait的不是Add),阻塞在Wait上的Goroutine就不會阻塞,但計數器為負數時就會panic
- Done() 表示一個goroutine完成任務,WaitGroup減少1 (這邊是Add不是Wait)
- Wait() 此方法調用者會被阻塞,直到WaitGroup的計數值減小到0
- noCopy為輔助字段,主要用於輔助檢查工具vet
- 使用atomic.Uint64保證64位對齊,所以state能夠紀錄計數器的值和waiter的數量
- sema 用來喚醒waiter的信號量
state := wg.state.Add(uint64(delta) << 32) 計數器加delta值
v := int32(state >> 32) 右移32位,只保留計數器的值
w := uint32(state) waiter的數量
if w != 0 && delta > 0 && v == int32(delta)
檢查是否還有waiter在等待,如果有不應該再併發調用Add
wg.state.Store(0)
將計數器的值變為0,準備喚醒waiter
- 會先嘗試檢查計數器的值v
- v為0:不會發生阻塞,直接返回
- v不為0:原子操作state,把goroutine加入到waiter中
- 成功:被阻塞喚醒
- 失敗:進行循環檢查(因為可能同時有多個waiter調用Wait方法)
- 如果阻塞的Waiter被喚醒,理論上state的值為0(從Add方法實現可以看到,先清0再喚醒waiter),那就直接返回就好,因為state為0代表計數器的值也為0