🐛 Fix race conditions
This commit is contained in:
parent
80f455ae77
commit
b24cf3b9a0
3 changed files with 171 additions and 11 deletions
37
errgroup.go
37
errgroup.go
|
|
@ -28,15 +28,15 @@ type Group struct {
|
|||
|
||||
wg sync.WaitGroup
|
||||
|
||||
sem chan token
|
||||
sem atomic.Value
|
||||
|
||||
errOnce sync.Once
|
||||
err atomic.Value
|
||||
}
|
||||
|
||||
func (g *Group) done() {
|
||||
if g.sem != nil {
|
||||
<-g.sem
|
||||
if sem := g.sema(); sem != nil {
|
||||
<-sem
|
||||
}
|
||||
g.wg.Done()
|
||||
}
|
||||
|
|
@ -51,6 +51,20 @@ func WithContext(ctx context.Context) (*Group, context.Context) {
|
|||
return &Group{cancel: cancel}, ctx
|
||||
}
|
||||
|
||||
type semContainer struct{ sem chan token }
|
||||
|
||||
func (g *Group) sema() chan token {
|
||||
v := g.sem.Load()
|
||||
if v == nil {
|
||||
return nil
|
||||
}
|
||||
return v.(semContainer).sem
|
||||
}
|
||||
|
||||
func (g *Group) setSema(ch chan token) {
|
||||
g.sem.Store(semContainer{ch})
|
||||
}
|
||||
|
||||
func (g *Group) error() error {
|
||||
v := g.err.Load()
|
||||
if v == nil {
|
||||
|
|
@ -94,8 +108,8 @@ func (g *Group) Go(f func() error) {
|
|||
if g.error() != nil {
|
||||
return
|
||||
}
|
||||
if g.sem != nil {
|
||||
g.sem <- token{}
|
||||
if sem := g.sema(); sem != nil {
|
||||
sem <- token{}
|
||||
}
|
||||
|
||||
g.wg.Add(1)
|
||||
|
|
@ -126,9 +140,9 @@ func (g *Group) TryGo(f func() error) bool {
|
|||
if g.error() != nil {
|
||||
return false
|
||||
}
|
||||
if g.sem != nil {
|
||||
if sem := g.sema(); sem != nil {
|
||||
select {
|
||||
case g.sem <- token{}:
|
||||
case sem <- token{}:
|
||||
// Note: this allows barging iff channels in general allow barging.
|
||||
default:
|
||||
return false
|
||||
|
|
@ -159,12 +173,13 @@ func (egerr *ErrgroupLimitError) Error() string {
|
|||
// The limit must not be modified while any goroutines in the group are active.
|
||||
func (g *Group) SetLimit(n int) {
|
||||
if n < 0 {
|
||||
g.sem = nil
|
||||
g.setSema(nil)
|
||||
return
|
||||
}
|
||||
if len(g.sem) != 0 {
|
||||
var err error = &ErrgroupLimitError{len(g.sem)}
|
||||
|
||||
if sem := g.sema(); sem != nil && len(sem) != 0 {
|
||||
var err error = &ErrgroupLimitError{len(sem)}
|
||||
panic(err)
|
||||
}
|
||||
g.sem = make(chan token, n)
|
||||
g.setSema(make(chan token, n))
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue