69 lines
1.6 KiB
Go
69 lines
1.6 KiB
Go
// Package sync extends basic synchronization primitives.
|
|
package sync
|
|
|
|
import (
|
|
"sync"
|
|
)
|
|
|
|
// 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.
|
|
//
|
|
// WaitGroups in the sync package do not allow adding or
|
|
// subtracting from the counter while another goroutine is
|
|
// waiting, while this one does.
|
|
//
|
|
// A WaitGroup must not be copied after first use.
|
|
//
|
|
// In the terminology of the Go memory model, a call to Done
|
|
type WaitGroup struct {
|
|
c int64
|
|
mutex sync.Mutex
|
|
cond *sync.Cond
|
|
}
|
|
|
|
// NewWaitGroup creates a new WaitGroup.
|
|
func NewWaitGroup() *WaitGroup {
|
|
wg := &WaitGroup{}
|
|
wg.cond = sync.NewCond(&wg.mutex)
|
|
return wg
|
|
}
|
|
|
|
// 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.
|
|
func (wg *WaitGroup) Add(delta int) {
|
|
wg.mutex.Lock()
|
|
defer wg.mutex.Unlock()
|
|
wg.c += int64(delta)
|
|
if wg.c < 0 {
|
|
panic("udp: negative WaitGroup counter") // nolint
|
|
}
|
|
wg.cond.Signal()
|
|
}
|
|
|
|
// Done decrements the WaitGroup counter by one.
|
|
func (wg *WaitGroup) Done() {
|
|
wg.Add(-1)
|
|
}
|
|
|
|
// Wait blocks until the WaitGroup counter is zero.
|
|
func (wg *WaitGroup) Wait() {
|
|
wg.mutex.Lock()
|
|
defer wg.mutex.Unlock()
|
|
for {
|
|
c := wg.c
|
|
switch {
|
|
case c == 0:
|
|
// wake another goroutine if there is one
|
|
wg.cond.Signal()
|
|
return
|
|
case c < 0:
|
|
panic("udp: negative WaitGroup counter") // nolint
|
|
}
|
|
wg.cond.Wait()
|
|
}
|
|
}
|