Source File
waitgroup.go
Belonging Package
sync
// Copyright 2011 The Go Authors. All rights reserved.// Use of this source code is governed by a BSD-style// license that can be found in the LICENSE file.package syncimport ()// A WaitGroup waits for a collection of goroutines to finish.// The main goroutine calls Add to set the number of// goroutines to wait for. Then each of the goroutines// runs and calls Done when finished. At the same time,// Wait can be used to block until all goroutines have finished.//// A WaitGroup must not be copied after first use.//// In the terminology of the Go memory model, a call to Done// “synchronizes before” the return of any Wait call that it unblocks.type WaitGroup struct {noCopy noCopystate atomic.Uint64 // high 32 bits are counter, low 32 bits are waiter count.sema uint32}// Add adds delta, which may be negative, to the WaitGroup counter.// If the counter becomes zero, all goroutines blocked on Wait are released.// If the counter goes negative, Add panics.//// Note that calls with a positive delta that occur when the counter is zero// must happen before a Wait. Calls with a negative delta, or calls with a// positive delta that start when the counter is greater than zero, may happen// at any time.// Typically this means the calls to Add should execute before the statement// creating the goroutine or other event to be waited for.// If a WaitGroup is reused to wait for several independent sets of events,// new Add calls must happen after all previous Wait calls have returned.// See the WaitGroup example.func ( *WaitGroup) ( int) {if race.Enabled {if < 0 {// Synchronize decrements with Wait.race.ReleaseMerge(unsafe.Pointer())}race.Disable()defer race.Enable()}:= .state.Add(uint64() << 32):= int32( >> 32):= uint32()if race.Enabled && > 0 && == int32() {// The first increment must be synchronized with Wait.// Need to model this as a read, because there can be// several concurrent wg.counter transitions from 0.race.Read(unsafe.Pointer(&.sema))}if < 0 {panic("sync: negative WaitGroup counter")}if != 0 && > 0 && == int32() {panic("sync: WaitGroup misuse: Add called concurrently with Wait")}if > 0 || == 0 {return}// This goroutine has set counter to 0 when waiters > 0.// Now there can't be concurrent mutations of state:// - Adds must not happen concurrently with Wait,// - Wait does not increment waiters if it sees counter == 0.// Still do a cheap sanity check to detect WaitGroup misuse.if .state.Load() != {panic("sync: WaitGroup misuse: Add called concurrently with Wait")}// Reset waiters count to 0..state.Store(0)for ; != 0; -- {runtime_Semrelease(&.sema, false, 0)}}// Done decrements the WaitGroup counter by one.func ( *WaitGroup) () {.Add(-1)}// Wait blocks until the WaitGroup counter is zero.func ( *WaitGroup) () {if race.Enabled {race.Disable()}for {:= .state.Load():= int32( >> 32):= uint32()if == 0 {// Counter is 0, no need to wait.if race.Enabled {race.Enable()race.Acquire(unsafe.Pointer())}return}// Increment waiters count.if .state.CompareAndSwap(, +1) {if race.Enabled && == 0 {// Wait must be synchronized with the first Add.// Need to model this is as a write to race with the read in Add.// As a consequence, can do the write only for the first waiter,// otherwise concurrent Waits will race with each other.race.Write(unsafe.Pointer(&.sema))}runtime_Semacquire(&.sema)if .state.Load() != 0 {panic("sync: WaitGroup is reused before previous Wait has returned")}if race.Enabled {race.Enable()race.Acquire(unsafe.Pointer())}return}}}
![]() |
The pages are generated with Golds v0.6.7. (GOOS=linux GOARCH=amd64) Golds is a Go 101 project developed by Tapir Liu. PR and bug reports are welcome and can be submitted to the issue list. Please follow @Go100and1 (reachable from the left QR code) to get the latest news of Golds. |