better lock practice in sharedcalls

master
kevin 4 years ago
parent 93f430a449
commit a22bcc84a3

@ -33,35 +33,42 @@ func NewSharedCalls() SharedCalls {
} }
func (g *sharedGroup) Do(key string, fn func() (interface{}, error)) (interface{}, error) { func (g *sharedGroup) Do(key string, fn func() (interface{}, error)) (interface{}, error) {
g.lock.Lock() c, done := g.createCall(key, fn)
if c, ok := g.calls[key]; ok { if done {
g.lock.Unlock()
c.wg.Wait()
return c.val, c.err return c.val, c.err
} }
c := g.makeCall(key, fn) g.makeCall(c, key, fn)
return c.val, c.err return c.val, c.err
} }
func (g *sharedGroup) DoEx(key string, fn func() (interface{}, error)) (val interface{}, fresh bool, err error) { func (g *sharedGroup) DoEx(key string, fn func() (interface{}, error)) (val interface{}, fresh bool, err error) {
g.lock.Lock() c, done := g.createCall(key, fn)
if c, ok := g.calls[key]; ok { if done {
g.lock.Unlock()
c.wg.Wait()
return c.val, false, c.err return c.val, false, c.err
} }
c := g.makeCall(key, fn) g.makeCall(c, key, fn)
return c.val, true, c.err return c.val, true, c.err
} }
func (g *sharedGroup) makeCall(key string, fn func() (interface{}, error)) *call { func (g *sharedGroup) createCall(key string, fn func() (interface{}, error)) (c *call, done bool) {
c := new(call) g.lock.Lock()
if c, ok := g.calls[key]; ok {
g.lock.Unlock()
c.wg.Wait()
return c, true
}
c = new(call)
c.wg.Add(1) c.wg.Add(1)
g.calls[key] = c g.calls[key] = c
g.lock.Unlock() g.lock.Unlock()
return c, false
}
func (g *sharedGroup) makeCall(c *call, key string, fn func() (interface{}, error)) {
defer func() { defer func() {
// delete key first, done later. can't reverse the order, because if reverse, // delete key first, done later. can't reverse the order, because if reverse,
// another Do call might wg.Wait() without get notified with wg.Done() // another Do call might wg.Wait() without get notified with wg.Done()
@ -72,5 +79,4 @@ func (g *sharedGroup) makeCall(key string, fn func() (interface{}, error)) *call
}() }()
c.val, c.err = fn() c.val, c.err = fn()
return c
} }

Loading…
Cancel
Save