Skip to content

Commit 822031d

Browse files
qiulaidongfenggopherbot
authored andcommitted
sync: add WaitGroup.Go
Fixes #63796 Change-Id: I2a941275dd64ef858cbf02d31a759fdc5c082ceb Reviewed-on: https://go-review.googlesource.com/c/go/+/662635 LUCI-TryBot-Result: Go LUCI <[email protected]> Reviewed-by: Alan Donovan <[email protected]> Auto-Submit: Carlos Amedee <[email protected]> Reviewed-by: Carlos Amedee <[email protected]>
1 parent d164776 commit 822031d

File tree

4 files changed

+60
-2
lines changed

4 files changed

+60
-2
lines changed

api/next/63796.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
pkg sync, method (*WaitGroup) Go(func()) #63769
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
[WaitGroup] has added a new method [WaitGroup.Go],
2+
that makes the common pattern of creating and counting goroutines more convenient.

src/sync/waitgroup.go

Lines changed: 45 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,35 @@ import (
1010
"unsafe"
1111
)
1212

13-
// A WaitGroup waits for a collection of goroutines to finish.
14-
// The main goroutine calls [WaitGroup.Add] to set the number of
13+
// A WaitGroup is a counting semaphore typically used to wait
14+
// for a group of goroutines to finish.
15+
//
16+
// The main goroutine calls [WaitGroup.Add] to set (or increase) the number of
1517
// goroutines to wait for. Then each of the goroutines
1618
// runs and calls [WaitGroup.Done] when finished. At the same time,
1719
// [WaitGroup.Wait] can be used to block until all goroutines have finished.
1820
//
21+
// This is a typical pattern of WaitGroup usage to
22+
// synchronize 3 goroutines, each calling the function f:
23+
//
24+
// var wg sync.WaitGroup
25+
// for range 3 {
26+
// wg.Add(1)
27+
// go func() {
28+
// defer wg.Done()
29+
// f()
30+
// }()
31+
// }
32+
// wg.Wait()
33+
//
34+
// For convenience, the [WaitGroup.Go] method simplifies this pattern to:
35+
//
36+
// var wg sync.WaitGroup
37+
// for range 3 {
38+
// wg.Go(f)
39+
// }
40+
// wg.Wait()
41+
//
1942
// A WaitGroup must not be copied after first use.
2043
//
2144
// In the terminology of [the Go memory model], a call to [WaitGroup.Done]
@@ -127,3 +150,23 @@ func (wg *WaitGroup) Wait() {
127150
}
128151
}
129152
}
153+
154+
// Go calls f in a new goroutine and adds that task to the WaitGroup.
155+
// When f returns, the task is removed from the WaitGroup.
156+
//
157+
// If the WaitGroup is empty, Go must happen before a [WaitGroup.Wait].
158+
// Typically, this simply means Go is called to start tasks before Wait is called.
159+
// If the WaitGroup is not empty, Go may happen at any time.
160+
// This means a goroutine started by Go may itself call Go.
161+
// If a WaitGroup is reused to wait for several independent sets of tasks,
162+
// new Go calls must happen after all previous Wait calls have returned.
163+
//
164+
// In the terminology of [the Go memory model](https://go.dev/ref/mem),
165+
// the return from f "synchronizes before" the return of any Wait call that it unblocks.
166+
func (wg *WaitGroup) Go(f func()) {
167+
wg.Add(1)
168+
go func() {
169+
defer wg.Done()
170+
f()
171+
}()
172+
}

src/sync/waitgroup_test.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,18 @@ func TestWaitGroupAlign(t *testing.T) {
9898
x.wg.Wait()
9999
}
100100

101+
func TestWaitGroupGo(t *testing.T) {
102+
wg := &WaitGroup{}
103+
var i int
104+
wg.Go(func() {
105+
i++
106+
})
107+
wg.Wait()
108+
if i != 1 {
109+
t.Fatalf("got %d, want 1", i)
110+
}
111+
}
112+
101113
func BenchmarkWaitGroupUncontended(b *testing.B) {
102114
type PaddedWaitGroup struct {
103115
WaitGroup

0 commit comments

Comments
 (0)