package locker import ( "sync" ) type Elem struct { Pipe chan bool Usage int } func NewElem() *Elem { return &Elem{ Pipe: make(chan bool, 1), } } type Locker struct { mtx sync.Mutex lMap map[string]*Elem } func NewLocker() *Locker { lock := &Locker{ lMap: make(map[string]*Elem), } return lock } func (lock *Locker) WaitAndLock(name string) { lock.mtx.Lock() p, exist := lock.lMap[name] if !exist { p = NewElem() lock.lMap[name] = p p.Pipe <- true } p.Usage += 1 lock.mtx.Unlock() select { case <-p.Pipe: // NOP } } func (lock *Locker) Done(name string) { lock.mtx.Lock() p, exist := lock.lMap[name] if exist { p.Pipe <- true if p.Usage > 0 { p.Usage -= 1 } } garbageKeys := make([]string, 0) for key, _ := range lock.lMap { elem := lock.lMap[key] if elem.Usage == 0 && key != name { garbageKeys = append(garbageKeys, key) } } for _, key := range garbageKeys { delete(lock.lMap, key) } lock.mtx.Unlock() }