This is a creation in Article, where the information may have evolved or changed.
Sync for Golang 1.9. Waitgroup for analysis, the same as the Golang 1.10, except panic that it will be changed to throw something other than the others. Source code location: sync\waitgroup.go .
Structural body
type WaitGroup struct {noCopy noCopy // noCopy可以嵌入到结构中,在第一次使用后不可复制,使用go vet作为检测使用// 位值:高32位是计数器,低32位是goroution等待计数。// 64位的原子操作需要64位的对齐,但是32位。编译器不能确保它,所以分配了12个byte对齐的8个byte作为状态。state1 [12]byte // byte=uint8范围:0~255,只取前8个元素。转为2进制:0000 0000,0000 0000... ...0000 0000sema uint32 // 信号量,用于唤醒goroution}
I do not know whether people like me, whether it is the use of Java Countdownlatch or Golang Waitgroup, will be questioned, can be loaded with multiple threads | co-process wait? After reading the source can answer, can be installed
1111 1111 1111 ... 1111\________32___________/
2^32 a lot of spicy! So you don't have to worry about being blown up in a single case.
Function
The following code has removed the race code that is not related to the core code.
Add
Add or decrease the number of waiting goroutine.
Add the delta, which may be negative, to the Waitgroup counter.
- If the counter becomes 0, all blocked Goroutines will be released.
- If the counter becomes negative, it increases panic.
func (WG *waitgroup) Add (delta int) {//Gets the decimal value of the binary corresponding to the elements in the wg.state1 array statep: = Wg.state ()//High 32 bits is the counter state : = Atomic. AddUint64 (Statep, UInt64 (delta) <<32)//Get counter V: = Int32 (State >> +) W: = UInt32 (state)//counter is negative, reported Panicif v < ; 0 {Panic ("sync:negative waitgroup Counter")}//Add and wait for concurrent calls, Report Panicif W! = 0 && Delta > 0 && v = = Int32 (de LTA) {Panic ("Sync:waitgroup Misuse:add called concurrently with Wait")}//counter added successfully if v > 0 | | W = = 0 {return}//When waiting for counter > 0 o'clock, while Goroutine is set to 0. There can be no simultaneous state mutation at this time://-The increase cannot occur simultaneously with the wait,//-if the counter counter = = 0, the wait counter is no longer incremented if *statep! = states {Panic ("Sync:waitgroup Misuse:ad D called concurrently with Wait ")}//Reset waiters count to 0.*statep = 0for; W! = 0; w--{//is intended as a simple wakeup primitive for simultaneous use. True to wake up the first goroutineruntime_semrelease (&wg.sema, False)}} that is queued in the wait queue
// unsafe.Pointer其实就是类似C的void *,在golang中是用于各种指针相互转换的桥梁。// uintptr是golang的内置类型,是能存储指针的整型,uintptr的底层类型是int,它和unsafe.Pointer可相互转换。// uintptr和unsafe.Pointer的区别就是:unsafe.Pointer只是单纯的通用指针类型,用于转换不同类型指针,它不可以参与指针运算;// 而uintptr是用于指针运算的,GC 不把 uintptr 当指针,也就是说 uintptr 无法持有对象,uintptr类型的目标会被回收。// state()函数可以获取到wg.state1数组中元素组成的二进制对应的十进制的值func (wg *WaitGroup) state() *uint64 {if uintptr(unsafe.Pointer(&wg.state1))%8 == 0 {return (*uint64)(unsafe.Pointer(&wg.state1))} else {return (*uint64)(unsafe.Pointer(&wg.state1[4]))}}
Done
Equivalent to add (-1).
func (wg *WaitGroup) Done() { // 计数器减一wg.Add(-1)}
Wait
Execution is blocked until all the Waitgroup number becomes 0.
func (wg *WaitGroup) Wait() {// 获取到wg.state1数组中元素组成的二进制对应的十进制的值statep := wg.state()// cas算法for {state := atomic.LoadUint64(statep)// 高32位是计数器v := int32(state >> 32)w := uint32(state)// 计数器为0,结束等待if v == 0 {// Counter is 0, no need to wait.return}// 增加等待goroution计数,对低32位加1,不需要移位if atomic.CompareAndSwapUint64(statep, state, state+1) {// 目的是作为一个简单的sleep原语,以供同步使用runtime_Semacquire(&wg.sema)if *statep != 0 {panic("sync: WaitGroup is reused before previous Wait has returned")}return}}}
Precautions for use
- Waitgroup cannot guarantee multiple Goroutine execution order
- Waitgroup cannot specify a fixed number of goroutine