WaitGroup is reused before previous Wait has returned
写了一个Go的代码啊,但是在执行过程中出现WaitGroup is reused before previous Wait has returnedimport ("fmt""strconv""sync")var m2 sync.Mapvar swg sync.WaitGroupfunc main(){for i := 0; i < 20; i++ {go func(i int) {swg.
·
学习Go语言时,写了一个Go的代码,但是在执行过程中出现WaitGroup is reused before previous Wait has returned
import (
"fmt"
"strconv"
"sync"
)
var m2 sync.Map
var swg sync.WaitGroup
func main(){
for i := 0; i < 20; i++ {
go func(i int) {
swg.Add(1)
key := strconv.Itoa(i)
m2.Store(key, i)
value, ok := m2.Load(key)
if !ok {
fmt.Println("There are something error")
}
fmt.Printf("key:%s value:%d\n", key, value)
swg.Done()
}(i)
}
swg.Wait()
}
翻看WaitGroup源码,找到Wait
func (wg *WaitGroup) Wait() {
statep, semap := wg.state()
if race.Enabled {
_ = *statep // trigger nil deref early
race.Disable()
}
for {
state := atomic.LoadUint64(statep)
v := int32(state >> 32)
w := uint32(state)
if v == 0 {
// Counter is 0, no need to wait.
if race.Enabled {
race.Enable()
race.Acquire(unsafe.Pointer(wg))
}
return
}
// Increment waiters count.
if atomic.CompareAndSwapUint64(statep, state, state+1) {
if race.Enabled && w == 0 {
// Wait must be synchronized with the first Add.
// Need to model this is as a write to race with the read in Add.
// As a consequence, can do the write only for the first waiter,
// otherwise concurrent Waits will race with each other.
race.Write(unsafe.Pointer(semap))
}
runtime_Semacquire(semap)
if *statep != 0 {
panic("sync: WaitGroup is reused before previous Wait has returned")
}
if race.Enabled {
race.Enable()
race.Acquire(unsafe.Pointer(wg))
}
return
}
}
}
翻阅源码发现:
在调用Wait时会进入waitblock,直到waitgroup 计数器变为0
而在waitgroup计数器变为0时,如果外部调用了add方法将waitgroup计数器的值变为了非0.那么就会报错
runtime_Semacquire(semap)
if *statep != 0 {
panic("sync: WaitGroup is reused before previous Wait has returned")
}
应用在我的代码上面,就是
go func(i int) {
swg.Add(1)
我将Add方法放在创建goroutine之后,可能前面除了一个goroutine以外的所有的goroutine都执行完了,主goroutine正要结束,也就是waitgroup计数器变为了0,这时又执行到了这个goroutine,并调用了Add方法,修改了waitgroup计数器的值,就会出现如上的错误
解决办法就是先将waitgroup计数器+1,然后在开启一个goroutine
即将Add方法放在go func的前面。
更多推荐
所有评论(0)