WaitGroup
数据结构
WaitGroup 的数据结构如下,包含长度为 3 的 uint32 数组。
1 | type WaitGroup struct { |
其中,数组包含了一个 state(由两个计数器组成)和一个信号量:
- counter: 当前还未执行结束的 goroutine 计数器。
- waiter:等候者的数量。
- semaphore:信号量。
也可以认为是 state 的类型为 uint64,而信号量的类型为 uint32。
Add Wait Done 实现
WaitGroup 实现了三个方法:
- Add(delta int):把 delta 的值加到 counter 中。
- Wait():waiter 的值增加 1,并阻塞等待信号量。
- Done():counter 递减 1,当 counter 的值等于 0 时,按照 waiter 数值释放相应次数信号量。
Add
Add 函数主要的流程如下:
- 首先把 delta 加到 counter 中,因为 delta 可能是负值,所以 counter 可能小于 0,当 counter 小于 0 时发出 panic。
- 接着如果 counter 等于 0,则释放 waiter 个信号量。
1 | func (wg *WaitGroup) Add(delta int) { |
Wait
Wait 函数主要的流程如下:
- 首先,累加 waiter 的数量。
- 接着,如果 counter 大于 0,则阻塞当前协程等待信号量。
1 | func (wg *WaitGroup) Wait() { |
这里用到了 CAS 算法,保证有多个 goroutine 同时执行 Wait() 时,也能正确累加 waiter。
Done
Done 只做了 counter 减一这一件事,这样当 counter 等于 0 时由 Add 函数唤醒等待的协程。
1 | func (wg *WaitGroup) Done() { |