自学内容网 自学内容网

go sync.WaitGroup

1、数据结构

type WaitGroup struct {
noCopy noCopy

state atomic.Uint64 // high 32 bits are counter, low 32 bits are waiter count.
sema  uint32
}

        计数器:原子变量,高32位用于为协程计数,低32位为等待计数(被Wait阻塞等待)。

        信号量:用于阻塞协程。

2、Add(x)

// 简化版

// Add adds delta, which may be negative, to the [WaitGroup] counter.
// If the counter becomes zero, all goroutines blocked on [WaitGroup.Wait] are released.
// If the counter goes negative, Add panics.

func (wg *WaitGroup) Add(delta int) {
state := wg.state.Add(uint64(delta) << 32)
v := int32(state >> 32)
w := uint32(state)

if v > 0 || w == 0 {
return
}

// Reset waiters count to 0.
wg.state.Store(0)
for ; w != 0; w-- {
runtime_Semrelease(&wg.sema, false, 0)
}
}

        通过原子操作对协程计数器加减,若协程计数变为0,则将等待计数设置为0,并释放所有被信号量阻塞的协程。

3、Done()

// 简化版

// Done decrements the [WaitGroup] counter by one.

func (wg *WaitGroup) Done() {
wg.Add(-1)
}

        计数器-1

4、Wait()

// 简化版

// Wait blocks until the [WaitGroup] counter is zero.

func (wg *WaitGroup) Wait() {
for {
state := wg.state.Load()
v := int32(state >> 32)
w := uint32(state)
if v == 0 {
// Counter is 0, no need to wait.
return
}
// Increment waiters count.
if wg.state.CompareAndSwap(state, state+1) {
runtime_Semacquire(&wg.sema)
return
}
}
}

        若协程计数为0,则直接跳过。

        若协程计数非0,则通过CAS将等待计数+1,并通过信号量阻塞协程。


原文地址:https://blog.csdn.net/weixin_41565755/article/details/144057978

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!