github.com/angenalZZZ/gofunc@v0.0.0-20210507121333-48ff1be3917b/f/lock.go (about)

     1  /*
     2  Package locker is a simple package to manage named ReadWrite mutexes. These
     3  appear to be especially useful for synchronizing access to session based
     4  information in web applications.
     5  
     6  The common use case is to use the package level functions, which use a package
     7  level set of locks (safe to use from multiple goroutines simultaneously).
     8  However, you may also create a new separate set of locks.
     9  
    10  All locks are implemented with read-write mutexes. To use them like a regular
    11  mutex, simply ignore the RLock/RUnlock functions.
    12  */
    13  package f
    14  
    15  // github.com/BurntSushi/locker
    16  // BUG: The locker here can grow without bound in long running
    17  // programs. Since it's intended to be used in web applications, this is a
    18  // major problem. Figure out a way to keep the locker lean.
    19  
    20  import (
    21  	"sync"
    22  )
    23  
    24  // Locker represents the set of named ReadWrite mutexes. It is safe to access
    25  // from multiple goroutines simultaneously.
    26  type Locker struct {
    27  	locks   map[string]*sync.RWMutex
    28  	locksRW *sync.RWMutex
    29  }
    30  
    31  var locker *Locker
    32  
    33  func init() {
    34  	locker = NewLocker()
    35  }
    36  
    37  func Lock(key string)    { locker.Lock(key) }
    38  func Unlock(key string)  { locker.Unlock(key) }
    39  func RLock(key string)   { locker.RLock(key) }
    40  func RUnlock(key string) { locker.RUnlock(key) }
    41  func DeLock(key string)  { locker.deleteLock(key) }
    42  
    43  func NewLocker() *Locker {
    44  	return &Locker{
    45  		locks:   make(map[string]*sync.RWMutex),
    46  		locksRW: new(sync.RWMutex),
    47  	}
    48  }
    49  
    50  func (l *Locker) Lock(key string) {
    51  	lk, ok := l.getLock(key)
    52  	if !ok {
    53  		lk = l.newLock(key)
    54  	}
    55  	lk.Lock()
    56  }
    57  
    58  func (l *Locker) Unlock(key string) {
    59  	lk, ok := l.getLock(key)
    60  	if ok {
    61  		lk.Unlock()
    62  	}
    63  }
    64  
    65  func (l *Locker) RLock(key string) {
    66  	lk, ok := l.getLock(key)
    67  	if !ok {
    68  		lk = l.newLock(key)
    69  	}
    70  	lk.RLock()
    71  }
    72  
    73  func (l *Locker) RUnlock(key string) {
    74  	lk, ok := l.getLock(key)
    75  	if ok {
    76  		lk.RUnlock()
    77  	}
    78  }
    79  
    80  func (l *Locker) newLock(key string) *sync.RWMutex {
    81  	l.locksRW.Lock()
    82  	defer l.locksRW.Unlock()
    83  
    84  	if lk, ok := l.locks[key]; ok {
    85  		return lk
    86  	}
    87  	lk := new(sync.RWMutex)
    88  	l.locks[key] = lk
    89  	return lk
    90  }
    91  
    92  func (l *Locker) getLock(key string) (*sync.RWMutex, bool) {
    93  	l.locksRW.RLock()
    94  	defer l.locksRW.RUnlock()
    95  
    96  	lock, ok := l.locks[key]
    97  	return lock, ok
    98  }
    99  
   100  func (l *Locker) deleteLock(key string) {
   101  	l.locksRW.Lock()
   102  	defer l.locksRW.Unlock()
   103  
   104  	if _, ok := l.locks[key]; ok {
   105  		delete(l.locks, key)
   106  	}
   107  }