diff options
| author | qiulaidongfeng <2645477756@qq.com> | 2025-04-03 23:10:16 +0800 |
|---|---|---|
| committer | Gopher Robot <gobot@golang.org> | 2025-04-04 08:19:32 -0700 |
| commit | 822031dffc43567b4c60e12e77afe48a00028c0e (patch) | |
| tree | 4173d97b51245de336bef07847a14635ff6eb07b /src/sync | |
| parent | d164776615f75105c6f988900d798a0f476c4668 (diff) | |
| download | go-822031dffc43567b4c60e12e77afe48a00028c0e.tar.xz | |
sync: add WaitGroup.Go
Fixes #63796
Change-Id: I2a941275dd64ef858cbf02d31a759fdc5c082ceb
Reviewed-on: https://go-review.googlesource.com/c/go/+/662635
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Alan Donovan <adonovan@google.com>
Auto-Submit: Carlos Amedee <carlos@golang.org>
Reviewed-by: Carlos Amedee <carlos@golang.org>
Diffstat (limited to 'src/sync')
| -rw-r--r-- | src/sync/waitgroup.go | 47 | ||||
| -rw-r--r-- | src/sync/waitgroup_test.go | 12 |
2 files changed, 57 insertions, 2 deletions
diff --git a/src/sync/waitgroup.go b/src/sync/waitgroup.go index b50ecd94d3..8511f948ef 100644 --- a/src/sync/waitgroup.go +++ b/src/sync/waitgroup.go @@ -10,12 +10,35 @@ import ( "unsafe" ) -// A WaitGroup waits for a collection of goroutines to finish. -// The main goroutine calls [WaitGroup.Add] to set the number of +// A WaitGroup is a counting semaphore typically used to wait +// for a group of goroutines to finish. +// +// The main goroutine calls [WaitGroup.Add] to set (or increase) the number of // goroutines to wait for. Then each of the goroutines // runs and calls [WaitGroup.Done] when finished. At the same time, // [WaitGroup.Wait] can be used to block until all goroutines have finished. // +// This is a typical pattern of WaitGroup usage to +// synchronize 3 goroutines, each calling the function f: +// +// var wg sync.WaitGroup +// for range 3 { +// wg.Add(1) +// go func() { +// defer wg.Done() +// f() +// }() +// } +// wg.Wait() +// +// For convenience, the [WaitGroup.Go] method simplifies this pattern to: +// +// var wg sync.WaitGroup +// for range 3 { +// wg.Go(f) +// } +// wg.Wait() +// // A WaitGroup must not be copied after first use. // // In the terminology of [the Go memory model], a call to [WaitGroup.Done] @@ -127,3 +150,23 @@ func (wg *WaitGroup) Wait() { } } } + +// Go calls f in a new goroutine and adds that task to the WaitGroup. +// When f returns, the task is removed from the WaitGroup. +// +// If the WaitGroup is empty, Go must happen before a [WaitGroup.Wait]. +// Typically, this simply means Go is called to start tasks before Wait is called. +// If the WaitGroup is not empty, Go may happen at any time. +// This means a goroutine started by Go may itself call Go. +// If a WaitGroup is reused to wait for several independent sets of tasks, +// new Go calls must happen after all previous Wait calls have returned. +// +// In the terminology of [the Go memory model](https://go.dev/ref/mem), +// the return from f "synchronizes before" the return of any Wait call that it unblocks. +func (wg *WaitGroup) Go(f func()) { + wg.Add(1) + go func() { + defer wg.Done() + f() + }() +} diff --git a/src/sync/waitgroup_test.go b/src/sync/waitgroup_test.go index 4ded218d2d..8a948f8972 100644 --- a/src/sync/waitgroup_test.go +++ b/src/sync/waitgroup_test.go @@ -98,6 +98,18 @@ func TestWaitGroupAlign(t *testing.T) { x.wg.Wait() } +func TestWaitGroupGo(t *testing.T) { + wg := &WaitGroup{} + var i int + wg.Go(func() { + i++ + }) + wg.Wait() + if i != 1 { + t.Fatalf("got %d, want 1", i) + } +} + func BenchmarkWaitGroupUncontended(b *testing.B) { type PaddedWaitGroup struct { WaitGroup |
