WaitGroup解决的就是并发-等待问题。通过设置checkpoint,等所有的goroutine都执行完成才能继续。
很多操作系统和编程语言中都提供了类似的并发原语。
Linux中的barrier、Pthread中的barrier、C++中的std:barrier、Java中的CiclicBarrier和CountDownLatch等。
func (wg *WaitGroup) Add(delta int) func (wg *WaitGroup) Done() func (wg *WaitGroup) Wait()WaitGroup实现
type WaitGroup struct {
noCopty noCopty //避免复制使用,辅助vet工具检查
state1 [3]uint32 //包含waitgroup的计数、阻塞在waiter检查点的计数、信号量
}
state1字段说明:
因为对64位整数的原子操作要求整数的地址是64位对齐的,所以针对64位和32位环境的state字段的组成是不一样的。
针对64位:
state1[0]:waiter数
state1[1]:计数值
state1[2]:信号量
针对32位:
state1[0]:信号量
state1[1]:waiter数
state1[2]:计数值
Add、Done、Wait三个方法的实现:
Add方法主要就是操作state1的计数部分。
Done方法实际就是Add(-1)
Wait方法就是不断检查state的值。
1.计数器设置为负值,有2种情况:Add(-1)、Done()调用过多,和Add()不匹配
2.Add()时机不对
3.前一个wait还没有结束,就重用waitGroup
如何避免错误使用WaitGroup,尽量做到5点:
1.不重用waitGroup
2.保证所有的Add方法在wait前
3.不传到负数给Add(),只通过Done操作
4.保证Add的计数值和Done数量匹配
5.不遗漏Done方法的调用,否则会hang住。
noCopy:不能做复制使用,辅助的、提供给vet检查用的类型。



