Skip to content

Commit 109370e

Browse files
Add WaitGroup.WaitRelease(releaseFunc func()),
The passed in `releaseFunc` will be called immediately if no need to wait, or right before wait(`runtime_Semacquire`). This can be useful when some resources can be released before wait, e.g, when `Add/Wait` are synchronised by RWMutex, where `Add` only happens while holding `RLock` and `Wait` only happens while holding `Lock`. Here's a concrete example: https://github.com/zhiqiangxu/util/blob/master/closer/state.go#L58 Fixed #36349
1 parent bbd25d2 commit 109370e

File tree

1 file changed

+11
-0
lines changed

1 file changed

+11
-0
lines changed

src/sync/waitgroup.go

+11
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,11 @@ func (wg *WaitGroup) Done() {
101101

102102
// Wait blocks until the WaitGroup counter is zero.
103103
func (wg *WaitGroup) Wait() {
104+
wg.WaitRelease(nil)
105+
}
106+
107+
// if releaseFunc is not nil, it will be called immediately if no need to wait, or right before wait.
108+
func (wg *WaitGroup) WaitRelease(releaseFunc func()) {
104109
statep, semap := wg.state()
105110
if race.Enabled {
106111
_ = *statep // trigger nil deref early
@@ -116,6 +121,9 @@ func (wg *WaitGroup) Wait() {
116121
race.Enable()
117122
race.Acquire(unsafe.Pointer(wg))
118123
}
124+
if releaseFunc != nil {
125+
releaseFunc()
126+
}
119127
return
120128
}
121129
// Increment waiters count.
@@ -127,6 +135,9 @@ func (wg *WaitGroup) Wait() {
127135
// otherwise concurrent Waits will race with each other.
128136
race.Write(unsafe.Pointer(semap))
129137
}
138+
if releaseFunc != nil {
139+
releaseFunc()
140+
}
130141
runtime_Semacquire(semap)
131142
if *statep != 0 {
132143
panic("sync: WaitGroup is reused before previous Wait has returned")

0 commit comments

Comments
 (0)