From a22bcc84a3a99dfcf11f6a50a730c138b01d70ba Mon Sep 17 00:00:00 2001 From: kevin Date: Wed, 30 Sep 2020 12:31:35 +0800 Subject: [PATCH] better lock practice in sharedcalls --- core/syncx/sharedcalls.go | 32 +++++++++++++++++++------------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/core/syncx/sharedcalls.go b/core/syncx/sharedcalls.go index 18344eb67..61d6e4fbb 100644 --- a/core/syncx/sharedcalls.go +++ b/core/syncx/sharedcalls.go @@ -33,35 +33,42 @@ func NewSharedCalls() SharedCalls { } func (g *sharedGroup) Do(key string, fn func() (interface{}, error)) (interface{}, error) { - g.lock.Lock() - if c, ok := g.calls[key]; ok { - g.lock.Unlock() - c.wg.Wait() + c, done := g.createCall(key, fn) + if done { return c.val, c.err } - c := g.makeCall(key, fn) + g.makeCall(c, key, fn) return c.val, c.err } func (g *sharedGroup) DoEx(key string, fn func() (interface{}, error)) (val interface{}, fresh bool, err error) { + c, done := g.createCall(key, fn) + if done { + return c.val, false, c.err + } + + g.makeCall(c, key, fn) + return c.val, true, c.err +} + +func (g *sharedGroup) createCall(key string, fn func() (interface{}, error)) (c *call, done bool) { g.lock.Lock() if c, ok := g.calls[key]; ok { g.lock.Unlock() c.wg.Wait() - return c.val, false, c.err + return c, true } - c := g.makeCall(key, fn) - return c.val, true, c.err -} - -func (g *sharedGroup) makeCall(key string, fn func() (interface{}, error)) *call { - c := new(call) + c = new(call) c.wg.Add(1) g.calls[key] = c g.lock.Unlock() + return c, false +} + +func (g *sharedGroup) makeCall(c *call, key string, fn func() (interface{}, error)) { defer func() { // 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() @@ -72,5 +79,4 @@ func (g *sharedGroup) makeCall(key string, fn func() (interface{}, error)) *call }() c.val, c.err = fn() - return c }