aboutsummaryrefslogtreecommitdiff
path: root/src/sync
diff options
context:
space:
mode:
authorqiulaidongfeng <2645477756@qq.com>2025-04-03 23:10:16 +0800
committerGopher Robot <gobot@golang.org>2025-04-04 08:19:32 -0700
commit822031dffc43567b4c60e12e77afe48a00028c0e (patch)
tree4173d97b51245de336bef07847a14635ff6eb07b /src/sync
parentd164776615f75105c6f988900d798a0f476c4668 (diff)
downloadgo-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.go47
-rw-r--r--src/sync/waitgroup_test.go12
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