waitgroup.go 1.6 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768
  1. // Package sync extends basic synchronization primitives.
  2. package sync
  3. import (
  4. "sync"
  5. )
  6. // A WaitGroup waits for a collection of goroutines to finish.
  7. // The main goroutine calls Add to set the number of
  8. // goroutines to wait for. Then each of the goroutines
  9. // runs and calls Done when finished. At the same time,
  10. // Wait can be used to block until all goroutines have finished.
  11. //
  12. // WaitGroups in the sync package do not allow adding or
  13. // subtracting from the counter while another goroutine is
  14. // waiting, while this one does.
  15. //
  16. // A WaitGroup must not be copied after first use.
  17. //
  18. // In the terminology of the Go memory model, a call to Done
  19. type WaitGroup struct {
  20. c int64
  21. mutex sync.Mutex
  22. cond *sync.Cond
  23. }
  24. // NewWaitGroup creates a new WaitGroup.
  25. func NewWaitGroup() *WaitGroup {
  26. wg := &WaitGroup{}
  27. wg.cond = sync.NewCond(&wg.mutex)
  28. return wg
  29. }
  30. // Add adds delta, which may be negative, to the WaitGroup counter.
  31. // If the counter becomes zero, all goroutines blocked on Wait are released.
  32. // If the counter goes negative, Add panics.
  33. func (wg *WaitGroup) Add(delta int) {
  34. wg.mutex.Lock()
  35. defer wg.mutex.Unlock()
  36. wg.c += int64(delta)
  37. if wg.c < 0 {
  38. panic("udp: negative WaitGroup counter") // nolint
  39. }
  40. wg.cond.Signal()
  41. }
  42. // Done decrements the WaitGroup counter by one.
  43. func (wg *WaitGroup) Done() {
  44. wg.Add(-1)
  45. }
  46. // Wait blocks until the WaitGroup counter is zero.
  47. func (wg *WaitGroup) Wait() {
  48. wg.mutex.Lock()
  49. defer wg.mutex.Unlock()
  50. for {
  51. c := wg.c
  52. switch {
  53. case c == 0:
  54. // wake another goroutine if there is one
  55. wg.cond.Signal()
  56. return
  57. case c < 0:
  58. panic("udp: negative WaitGroup counter") // nolint
  59. }
  60. wg.cond.Wait()
  61. }
  62. }