github.com/gitbookio/syncgroup@v0.0.0-20181003125046-3e73b2e6a972/conds.go (about) 1 package syncgroup 2 3 import ( 4 "fmt" 5 "sync" 6 ) 7 8 type CondGroup struct { 9 groups map[string]*sync.Cond 10 lock *sync.Mutex 11 } 12 13 func NewCondGroup() *CondGroup { 14 return &CondGroup{ 15 groups: map[string]*sync.Cond{}, 16 lock: &sync.Mutex{}, 17 } 18 } 19 20 // Lock returns true if the caller is the first to lock for this key 21 func (cg *CondGroup) Lock(key string) (first bool) { 22 // Lock to prevent race conditions 23 cg.lock.Lock() 24 25 // Check if we have an existing group 26 if cond, ok := cg.groups[key]; ok { 27 // Unlock so other callers can come in 28 cg.lock.Unlock() 29 cond.L.Lock() 30 cond.Wait() 31 cond.L.Unlock() 32 return false 33 } 34 // Unlock when we're finished setting up the new cond 35 defer cg.lock.Unlock() 36 37 // So we're the first caller 38 cond := sync.NewCond(&sync.Mutex{}) 39 40 // Add cond for group 41 cg.groups[key] = cond 42 43 return true 44 } 45 46 // Unlock should only be called by the original caller of "Lock" 47 // (that got the "true" return value) 48 // All subsequent callers to "Lock" are now unpaused 49 func (cg *CondGroup) Unlock(key string) error { 50 cg.lock.Lock() 51 defer cg.lock.Unlock() 52 53 cond, ok := cg.groups[key] 54 if !ok { 55 return fmt.Errorf("Can not unlock group %s: no lock exists", key) 56 } 57 58 // Free all wailting funcs 59 cond.Broadcast() 60 61 // Delete cond 62 delete(cg.groups, key) 63 64 return nil 65 }